diff --git a/assets/js/admin/admin-pointers.js b/assets/js/admin/admin-pointers.js deleted file mode 100644 index d32fd3d..0000000 --- a/assets/js/admin/admin-pointers.js +++ /dev/null @@ -1,57 +0,0 @@ -jQuery(document).ready(function($){ - - if(arePointersEnabled()){ - setTimeout(showSubscriptionPointers, 800); // give TinyMCE a chance to finish loading - } - - $('select#product-type').change(function(){ - if(arePointersEnabled()){ - $('#product-type').pointer('close'); - } - }); - - $('#_subscription_price, #_subscription_period, #_subscription_length').change(function(){ - if(arePointersEnabled()){ - $('.options_group.subscription_pricing').pointer('close'); - $('#product-type').pointer('close'); - } - }); - - function arePointersEnabled(){ - if($.getParameterByName('subscription_pointers')=='true'){ - return true; - } else { - return false; - } - } - - function showSubscriptionPointers(){ - $('#product-type').pointer({ - content: WCSPointers.typePointerContent, - position: { - edge: 'left', - align: 'center' - }, - close: function() { - if ($('select#product-type').val()==WCSubscriptions.productType){ - $('.options_group.subscription_pricing:not(".subscription_sync")').pointer({ - content: WCSPointers.pricePointerContent, - position: 'bottom', - close: function() { - dismissSubscriptionPointer(); - } - }).pointer('open'); - } - dismissSubscriptionPointer(); - } - }).pointer('open'); - } - - function dismissSubscriptionPointer(){ - $.post( ajaxurl, { - pointer: 'wcs_pointer', - action: 'dismiss-wp-pointer' - }); - } - -}); \ No newline at end of file diff --git a/assets/js/admin/admin.js b/assets/js/admin/admin.js deleted file mode 100644 index 0de3752..0000000 --- a/assets/js/admin/admin.js +++ /dev/null @@ -1,831 +0,0 @@ -jQuery(document).ready(function($){ - - $.extend({ - getParameterByName: function(name) { - name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]'); - var regexS = '[\\?&]' + name + '=([^&#]*)'; - var regex = new RegExp(regexS); - var results = regex.exec(window.location.search); - if(results == null) { - return ''; - } else { - return decodeURIComponent(results[1].replace(/\+/g, ' ')); - } - }, - daysInMonth: function( month ) { - // Intentionally choose a non-leap year because we want february to have only 28 days. - return new Date(Date.UTC(2001, month, 0)).getUTCDate(); - }, - showHideSubscriptionMeta: function(){ - if ($('select#product-type').val()==WCSubscriptions.productType) { - $('.show_if_simple').show(); - $('.grouping_options').hide(); - $('.options_group.pricing ._regular_price_field').hide(); - $('#sale-price-period').show(); - $('.hide_if_subscription').hide(); - $( 'input#_manage_stock' ).change(); - - if('day' == $('#_subscription_period').val()) { - $('.subscription_sync').hide(); - } - } else { - $('.options_group.pricing ._regular_price_field').show(); - $('#sale-price-period').hide(); - } - }, - showHideVariableSubscriptionMeta: function(){ - // In order for WooCommerce not to show the stock_status_field on variable subscriptions, make sure it has the hide if variable subscription class. - $( 'p.stock_status_field' ).addClass( 'hide_if_variable-subscription' ); - - if ($('select#product-type').val()=='variable-subscription') { - - $( 'input#_downloadable' ).prop( 'checked', false ); - $( 'input#_virtual' ).removeAttr( 'checked' ); - - $('.show_if_variable').show(); - $('.hide_if_variable').hide(); - $('.show_if_variable-subscription').show(); - $('.hide_if_variable-subscription').hide(); - $.showOrHideStockFields(); - - // Make the sale price row full width - $('.sale_price_dates_fields').prev('.form-row').addClass('form-row-full').removeClass('form-row-last'); - - } else { - - if ( 'variable' === $('select#product-type').val() ) { - $( '.show_if_variable-subscription' ).hide(); - $( '.show_if_variable' ).show(); - $( '.hide_if_variable' ).hide(); - $.showOrHideStockFields(); - } - - // Restore the sale price row width to half - $('.sale_price_dates_fields').prev('.form-row').removeClass('form-row-full').addClass('form-row-last'); - } - }, - showOrHideStockFields : function(){ - if ( $( 'input#_manage_stock' ).is( ':checked' ) ) { - $( 'div.stock_fields' ).show(); - } else { - $( 'div.stock_fields' ).hide(); - } - }, - setSubscriptionLengths: function(){ - $('[name^="_subscription_length"], [name^="variable_subscription_length"]').each(function(){ - var $lengthElement = $(this), - selectedLength = $lengthElement.val(), - hasSelectedLength = false, - matches = $lengthElement.attr('name').match(/\[(.*?)\]/), - periodSelector, - interval; - - if (matches) { // Variation - periodSelector = '[name="variable_subscription_period['+matches[1]+']"]'; - billingInterval = parseInt($('[name="variable_subscription_period_interval['+matches[1]+']"]').val()); - } else { - periodSelector = '#_subscription_period'; - billingInterval = parseInt($('#_subscription_period_interval').val()); - } - - $lengthElement.empty(); - - $.each(WCSubscriptions.subscriptionLengths[ $(periodSelector).val() ], function(length,description) { - if(parseInt(length) == 0 || 0 == (parseInt(length) % billingInterval)) { - $lengthElement.append($('').attr('value',length).text(description)); - } - }); - - $lengthElement.children('option').each(function(){ - if (this.value == selectedLength) { - hasSelectedLength = true; - return false; - } - }); - - if(hasSelectedLength){ - $lengthElement.val(selectedLength); - } else { - $lengthElement.val(0); - } - - }); - }, - setTrialPeriods: function(){ - $('[name^="_subscription_trial_length"], [name^="variable_subscription_trial_length"]').each(function(){ - var $trialLengthElement = $(this), - trialLength = $trialLengthElement.val(), - matches = $trialLengthElement.attr('name').match(/\[(.*?)\]/), - periodStrings; - - if (matches) { // Variation - $trialPeriodElement = $('[name="variable_subscription_trial_period['+matches[1]+']"]'); - } else { - $trialPeriodElement = $('#_subscription_trial_period'); - } - - selectedTrialPeriod = $trialPeriodElement.val(); - - $trialPeriodElement.empty(); - - if( parseInt(trialLength) == 1 ) { - periodStrings = WCSubscriptions.trialPeriodSingular; - } else { - periodStrings = WCSubscriptions.trialPeriodPlurals; - } - - $.each(periodStrings, function(key,description) { - $trialPeriodElement.append($('').attr('value',key).text(description)); - }); - - $trialPeriodElement.val(selectedTrialPeriod); - }); - }, - setSalePeriod: function(){ - $('#sale-price-period').fadeOut(80,function(){ - $('#sale-price-period').text($('#_subscription_period_interval option:selected').text()+' '+$('#_subscription_period option:selected').text()); - $('#sale-price-period').fadeIn(180); - }); - }, - setSyncOptions: function(periodField) { - - if ( typeof periodField != 'undefined' ) { - - if ($('select#product-type').val()=='variable-subscription') { - var $container = periodField.closest('.woocommerce_variable_attributes').find('.variable_subscription_sync'); - } else { - $container = periodField.closest('#general_product_data').find('.subscription_sync'); - } - - var $syncWeekMonthContainer = $container.find('.subscription_sync_week_month'), - $syncWeekMonthSelect = $syncWeekMonthContainer.find('select'), - $syncAnnualContainer = $container.find('.subscription_sync_annual'), - $varSubField = $container.find('[name^="variable_subscription_payment_sync_date"]'), - billingPeriod; - - if ($varSubField.length > 0) { // Variation - var matches = $varSubField.attr('name').match(/\[(.*?)\]/); - $subscriptionPeriodElement = $('[name="variable_subscription_period['+matches[1]+']"]'); - } else { - $subscriptionPeriodElement = $('#_subscription_period'); - } - - billingPeriod = $subscriptionPeriodElement.val(); - - if('day'==billingPeriod) { - $syncWeekMonthSelect.val(0); - $syncAnnualContainer.find('input[type="number"]').val(0).trigger('change'); - } else { - if('year'==billingPeriod) { - // Make sure the year sync fields are reset - $syncAnnualContainer.find('input[type="number"]').val(0).trigger('change'); - // And the week/month field has no option selected - $syncWeekMonthSelect.val(0); - } else { - // Make sure the year sync value is 0 - $syncAnnualContainer.find('input[type="number"]').val(0).trigger('change'); - - // And the week/month field has the appropriate options - $syncWeekMonthSelect.empty(); - $.each(WCSubscriptions.syncOptions[billingPeriod], function(key,description) { - $syncWeekMonthSelect.append($('').attr('value',key).text(description)); - }); - } - } - } - }, - showHideSyncOptions: function(){ - if($('#_subscription_payment_sync_date').length > 0 || $('.wc_input_subscription_payment_sync').length > 0){ - $('.subscription_sync, .variable_subscription_sync').each(function(){ // loop through all sync field groups - var $syncWeekMonthContainer = $(this).find('.subscription_sync_week_month'), - $syncWeekMonthSelect = $syncWeekMonthContainer.find('select'), - $syncAnnualContainer = $(this).find('.subscription_sync_annual'), - $varSubField = $(this).find('[name^="variable_subscription_payment_sync_date"]'), - $slideSwitch = false, // stop the general sync field group sliding down if editing a variable subscription - billingPeriod; - - if ($varSubField.length > 0) { // Variation - var matches = $varSubField.attr('name').match(/\[(.*?)\]/); - $subscriptionPeriodElement = $('[name="variable_subscription_period['+matches[1]+']"]'); - - if ($('select#product-type').val()=='variable-subscription') { - $slideSwitch = true; - } - } else { - $subscriptionPeriodElement = $('#_subscription_period'); - if ($('select#product-type').val()==WCSubscriptions.productType) { - $slideSwitch = true; - } - } - - billingPeriod = $subscriptionPeriodElement.val(); - - if('day'==billingPeriod) { - $(this).slideUp(400); - } else { - if ( $slideSwitch ) { - $(this).slideDown(400); - if('year'==billingPeriod) { - // Make sure the year sync fields are visible - $syncAnnualContainer.slideDown(400); - // And the week/month field is hidden - $syncWeekMonthContainer.slideUp(400); - } else { - // Make sure the year sync fields are hidden - $syncAnnualContainer.slideUp(400); - // And the week/month field is visible - $syncWeekMonthContainer.slideDown(400); - } - } - } - }); - } - }, - moveSubscriptionVariationFields: function(){ - $('#variable_product_options .variable_subscription_pricing').not('wcs_moved').each(function(){ - var $regularPriceRow = $(this).siblings('.variable_pricing'), - $trialSignUpRow = $(this).siblings('.variable_subscription_trial_sign_up'), - $saleDatesRow; - - $saleDatesRow = $(this).siblings('.variable_pricing'); - - // Add the subscription price fields above the standard price fields - $(this).insertBefore($regularPriceRow); - - $trialSignUpRow.insertBefore($(this)); - - // Replace the regular price field with the trial period field - $regularPriceRow.children(':first').addClass('hide_if_variable-subscription'); - - $(this).addClass('wcs_moved'); - }); - }, - getVariationBulkEditValue: function(variation_action){ - var value; - - switch( variation_action ) { - case 'variable_subscription_period': - case 'variable_subscription_trial_period': - value = prompt( WCSubscriptions.bulkEditPeriodMessage ); - break; - case 'variable_subscription_period_interval': - value = prompt( WCSubscriptions.bulkEditIntervalhMessage ); - break; - case 'variable_subscription_trial_length': - case 'variable_subscription_length': - value = prompt( WCSubscriptions.bulkEditLengthMessage ); - break; - case 'variable_subscription_sign_up_fee': - value = prompt( woocommerce_admin_meta_boxes_variations.i18n_enter_a_value ); - value = accounting.unformat( value, woocommerce_admin.mon_decimal_point ); - break; - } - - return value; - }, - disableEnableOneTimeShipping: function() { - var is_synced_or_has_trial = false; - - if ( 'variable-subscription' == $( 'select#product-type' ).val() ) { - var variations = $( '.woocommerce_variations .woocommerce_variation' ), - variations_checked = {}, - number_of_pages = $( '.woocommerce_variations' ).attr( 'data-total_pages' ); - - $(variations).each(function() { - var period_field = $( this ).find( '.wc_input_subscription_period' ), - variation_index = $( period_field ).attr( 'name' ).match(/\[(.*?)\]/), - variation_id = $( '[name="variable_post_id['+variation_index[1]+']"]' ).val(), - period = period_field.val(), - trial = $( this ).find( '.wc_input_subscription_trial_length' ).val(), - sync_date = 0; - - if ( 0 != trial ) { - is_synced_or_has_trial = true; - - // break - return false; - } - - if ( $( this ).find( '.variable_subscription_sync' ).length ) { - if ( 'month' == period || 'week' == period ) { - sync_date = $( '[name="variable_subscription_payment_sync_date['+variation_index[1]+']"]' ).val(); - } else if ( 'year' == period ) { - sync_date = $( '[name="variable_subscription_payment_sync_date_day['+variation_index[1]+']"]' ).val(); - } - - if ( 0 != sync_date ) { - is_synced_or_has_trial = true; - - // break - return false; - } - } - - variations_checked[ variation_index[1] ] = variation_id; - }); - - // if we haven't found a variation synced or with a trial at this point check the backend for other product variations - if ( ( number_of_pages > 1 || 0 == variations.length ) && false == is_synced_or_has_trial ) { - - var data = { - action: 'wcs_product_has_trial_or_is_synced', - product_id: woocommerce_admin_meta_boxes_variations.post_id, - variations_checked: variations_checked, - nonce: WCSubscriptions.oneTimeShippingCheckNonce, - }; - - $.ajax({ - url: WCSubscriptions.ajaxUrl, - data: data, - type: 'POST', - success : function( response ) { - $( '#_subscription_one_time_shipping' ).prop( 'disabled', response.is_synced_or_has_trial ); - // trigger an event now we have determined the one time shipping availability, in case we need to update the backend - $( '#_subscription_one_time_shipping' ).trigger( 'subscription_one_time_shipping_updated', [ response.is_synced_or_has_trial ] ); - } - }); - } else { - // trigger an event now we have determined the one time shipping availability, in case we need to update the backend - $( '#_subscription_one_time_shipping' ).trigger( 'subscription_one_time_shipping_updated', [ is_synced_or_has_trial ] ); - } - } else { - var trial = $( '#general_product_data #_subscription_trial_length' ).val(); - - if ( 0 != trial ) { - is_synced_or_has_trial = true; - } - - if ( $( '.subscription_sync' ).length && false == is_synced_or_has_trial ) { - var period = $( '#_subscription_period' ).val(), - sync_date = 0; - - if ( 'month' == period || 'week' == period ) { - sync_date = $( '#_subscription_payment_sync_date' ).val(); - } else if ( 'year' == period ) { - sync_date = $( '#_subscription_payment_sync_date_day' ).val(); - } - - if ( 0 != sync_date ) { - is_synced_or_has_trial = true; - } - } - } - - $( '#_subscription_one_time_shipping' ).prop( 'disabled', is_synced_or_has_trial ); - }, - showHideSubscriptionsPanels: function() { - var tab = $( 'div.panel-wrap' ).find( 'ul.wc-tabs li' ).eq( 0 ).find( 'a' ); - var panel = tab.attr( 'href' ); - var visible = $( panel ).children( '.options_group' ).filter( function() { - return 'none' != $( this ).css( 'display' ); - }); - if ( 0 != visible.length ) { - tab.click().parent().show(); - } - }, - maybeDisableRemoveLinks: function() { - $( '#variable_product_options .woocommerce_variation' ).each( function() { - var $removeLink = $( this ).find( '.remove_variation' ); - var can_remove_variation = ( '1' === $( this ).find( 'input.wcs-can-remove-variation').val() ); - var $msg = $( this ).find( '.wcs-can-not-remove-variation-msg' ); - - if ( ! can_remove_variation ) { - $msg.text( $removeLink.text() ); - $removeLink.replaceWith( $msg ); - } - } ); - }, - }); - - $('.options_group.pricing ._sale_price_field .description').prepend(''); - - // Move the subscription pricing section to the same location as the normal pricing section - $('.options_group.subscription_pricing').not('.variable_subscription_pricing .options_group.subscription_pricing').insertBefore($('.options_group.pricing:first')); - $('.show_if_subscription.clear').insertAfter($('.options_group.subscription_pricing')); - - // Move the subscription variation pricing section to a better location in the DOM on load - if($('#variable_product_options .variable_subscription_pricing').length > 0) { - $.moveSubscriptionVariationFields(); - } - // When a variation is added - $('#woocommerce-product-data').on('woocommerce_variations_added woocommerce_variations_loaded',function(){ - $.moveSubscriptionVariationFields(); - $.showHideVariableSubscriptionMeta(); - $.showHideSyncOptions(); - $.setSubscriptionLengths(); - }); - - if($('.options_group.pricing').length > 0) { - $.setSalePeriod(); - $.showHideSubscriptionMeta(); - $.showHideVariableSubscriptionMeta(); - $.setSubscriptionLengths(); - $.setTrialPeriods(); - $.showHideSyncOptions(); - $.disableEnableOneTimeShipping(); - $.showHideSubscriptionsPanels(); - } - - // Update subscription ranges when subscription period or interval is changed - $('#woocommerce-product-data').on('change','[name^="_subscription_period"], [name^="_subscription_period_interval"], [name^="variable_subscription_period"], [name^="variable_subscription_period_interval"]',function(){ - $.setSubscriptionLengths(); - $.showHideSyncOptions(); - $.setSyncOptions( $(this) ); - $.setSalePeriod(); - $.disableEnableOneTimeShipping(); - }); - - $('#woocommerce-product-data').on('propertychange keyup input paste change','[name^="_subscription_trial_length"], [name^="variable_subscription_trial_length"]',function(){ - $.setTrialPeriods(); - }); - - // Handles changes to sync date select/input for yearly subscription products. - $('#woocommerce-product-data').on('change', '[name^="_subscription_payment_sync_date_day"], [name^="variable_subscription_payment_sync_date_day"]', function() { - if ( 0 == $(this).val() ) { - $(this).siblings('[name^="_subscription_payment_sync_date_month"], [name^="variable_subscription_payment_sync_date_month"]').val(0); - $(this).prop('disabled', true); - } - }).on('change', '[name^="_subscription_payment_sync_date_month"], [name^="variable_subscription_payment_sync_date_month"]', function() { - var $syncDayOfMonthInput = $(this).siblings('[name^="_subscription_payment_sync_date_day"], [name^="variable_subscription_payment_sync_date_day"]'); - - if ( 0 < $(this).val() ) { - $syncDayOfMonthInput.val(1).attr({step: "1", min: "1", max: $.daysInMonth($(this).val())}).prop('disabled', false); - } else { - $syncDayOfMonthInput.val(0).trigger('change'); - } - }); - - $('body').bind('woocommerce-product-type-change',function(){ - $.showHideSubscriptionMeta(); - $.showHideVariableSubscriptionMeta(); - $.showHideSyncOptions(); - $.showHideSubscriptionsPanels(); - }); - - $('input#_downloadable, input#_virtual').change(function(){ - $.showHideSubscriptionMeta(); - $.showHideVariableSubscriptionMeta(); - }); - - // Make sure the "Used for variations" checkbox is visible when adding attributes to a variable subscription - $('body').on('woocommerce_added_attribute', function(){ - $.showHideVariableSubscriptionMeta(); - }); - - if($.getParameterByName('select_subscription')=='true'){ - $('select#product-type option[value="'+WCSubscriptions.productType+'"]').attr('selected', 'selected'); - $('select#product-type').select().change(); - } - - // Before saving a subscription product, validate the trial period - $('#post').submit(function(e){ - if ( WCSubscriptions.subscriptionLengths !== undefined ){ - var trialLength = $('#_subscription_trial_length').val(), - selectedTrialPeriod = $('#_subscription_trial_period').val(); - - if ( parseInt(trialLength) >= WCSubscriptions.subscriptionLengths[selectedTrialPeriod].length ) { - alert(WCSubscriptions.trialTooLongMessages[selectedTrialPeriod]); - $('#ajax-loading').hide(); - $('#publish').removeClass('button-primary-disabled'); - e.preventDefault(); - } - } - }); - - // Notify store manager that deleting an order via the Orders screen also deletes subscriptions associated with the orders - $('#posts-filter').submit(function(){ - if($('[name="post_type"]').val()=='shop_order'&&($('[name="action"]').val()=='trash'||$('[name="action2"]').val()=='trash')){ - var containsSubscription = false; - $('[name="post[]"]:checked').each(function(){ - if(true===$('.contains_subscription',$('#post-'+$(this).val())).data('contains_subscription')){ - containsSubscription = true; - } - return (false === containsSubscription); - }); - if(containsSubscription){ - return confirm(WCSubscriptions.bulkTrashWarning); - } - } - }); - - $('.order_actions .submitdelete').click(function(){ - if($('[name="contains_subscription"]').val()=='true'){ - return confirm(WCSubscriptions.trashWarning); - } - }); - - $( '#variable_product_options' ).on( 'click', '.delete.wcs-can-not-remove-variation-msg', function( e ) { - e.preventDefault(); - e.stopPropagation(); - } ); - - // Notify the store manager that trashing an order via the admin orders table row action also deletes the associated subscription if it exists - $( '.row-actions .submitdelete' ).click( function() { - var order = $( this ).closest( '.type-shop_order' ).attr( 'id' ); - - if ( true === $( '.contains_subscription', $( '#' + order ) ).data( 'contains_subscription' ) ) { - return confirm( WCSubscriptions.trashWarning ); - } - }); - - // Editing a variable product - $('#variable_product_options').on('change','[name^="variable_regular_price"]',function(){ - var matches = $(this).attr('name').match(/\[(.*?)\]/); - - if (matches) { - var loopIndex = matches[1]; - $('[name="variable_subscription_price['+loopIndex+']"]').val($(this).val()); - } - }); - - // Editing a variable product - $('#variable_product_options').on('change','[name^="variable_subscription_price"]',function(){ - var matches = $(this).attr('name').match(/\[(.*?)\]/); - - if (matches) { - var loopIndex = matches[1]; - $('[name="variable_regular_price['+loopIndex+']"]').val($(this).val()); - } - }); - - // Update hidden regular price when subscription price is update on simple products - $('#general_product_data').on('change', '[name^="_subscription_price"]', function() { - $('[name="_regular_price"]').val($(this).val()); - }); - - // Notify store manager that deleting an user via the Users screen also removed them from any subscriptions. - $('.users-php .submitdelete').on('click',function(){ - return confirm(WCSubscriptions.deleteUserWarning); - }); - - // WC 2.4+ variation bulk edit handling - $('select.variation_actions').on('variable_subscription_sign_up_fee_ajax_data variable_subscription_period_interval_ajax_data variable_subscription_period_ajax_data variable_subscription_trial_period_ajax_data variable_subscription_trial_length_ajax_data variable_subscription_length_ajax_data', function(event, data) { - bulk_action = event.type.replace(/_ajax_data/g,''); - value = $.getVariationBulkEditValue( bulk_action ); - - if ( 'variable_subscription_trial_length' == bulk_action ) { - // After variations have their trial length bulk updated in the backend, flag the One Time Shipping field as needing to be updated - $( '#_subscription_one_time_shipping' ).addClass( 'wcs_ots_needs_update' ); - } - - if ( value != null ) { - data.value = value; - } - return data; - }); - - var $allowSwitching = $( document.getElementById( 'woocommerce_subscriptions_allow_switching' ) ), - $syncRenewals = $( document.getElementById( 'woocommerce_subscriptions_sync_payments' ) ); - - // We're on the Subscriptions settings page - if ( $allowSwitching.length > 0 ) { - var allowSwitchingEnabled = $allowSwitching.find( 'input:checked' ).length, - $switchSettingsRows = $allowSwitching.parents( 'tr' ).siblings( 'tr' ), - $prorateFirstRenewal = $( document.getElementById( 'woocommerce_subscriptions_prorate_synced_payments' ) ), - $syncRows = $syncRenewals.parents( 'tr' ).siblings( 'tr' ), - $daysNoFeeRow = $( document.getElementById( 'woocommerce_subscriptions_days_no_fee' ) ).parents( 'tr' ), - $suspensionExtensionRow = $( '#woocommerce_subscriptions_recoup_suspension' ).parents( 'tr' ); - - // No animation for initial hiding when switching is disabled. - if ( 0 === allowSwitchingEnabled ) { - $switchSettingsRows.hide(); - } - - $allowSwitching.find( 'input' ).on( 'change', function() { - - var isEnabled = $allowSwitching.find( 'input:checked' ).length; - - if ( 0 === isEnabled ) { - $switchSettingsRows.fadeOut(); - } else if ( 0 === allowSwitchingEnabled ) { // switching was previously disabled, so settings will be hidden - $switchSettingsRows.fadeIn(); - } - allowSwitchingEnabled = isEnabled; - } ); - - // Show/hide suspension extension setting - $( '#woocommerce_subscriptions_max_customer_suspensions' ).on( 'change', function() { - if ( $( this ).val() > 0 ) { - $suspensionExtensionRow.show(); - } else { - $suspensionExtensionRow.hide(); - } - } ).change(); - - // No animation when initially hiding prorated rows. - if ( ! $syncRenewals.is( ':checked' ) ) { - $syncRows.hide(); - } else if ( 'recurring' !== $prorateFirstRenewal.val() ) { - $daysNoFeeRow.hide(); - } - - // Animate showing and hiding the synchronization rows. - $syncRenewals.on( 'change', function(){ - if ( $( this ).is( ':checked' ) ) { - $syncRows.not( $daysNoFeeRow ).fadeIn(); - $prorateFirstRenewal.change(); - } else { - $syncRows.fadeOut(); - } - } ); - - // Watch the Prorate First Renewal field for changes. - $prorateFirstRenewal.on( 'change', function() { - if ( 'recurring' === $( this ).val() ) { - $daysNoFeeRow.fadeIn(); - } else { - $daysNoFeeRow.fadeOut(); - } - } ); - } - - // Don't display the variation notice for variable subscription products - $( 'body' ).on( 'woocommerce-display-product-type-alert', function(e, select_val) { - if (select_val=='variable-subscription') { - return false; - } - }); - - $('.wcs_payment_method_selector').on('change', function() { - - var payment_method = $(this).val(); - - $('.wcs_payment_method_meta_fields').hide(); - $('#wcs_' + payment_method + '_fields').show(); - }); - - // After variations have been saved/updated in the backend, flag the One Time Shipping field as needing to be updated - $( '#woocommerce-product-data' ).on( 'woocommerce_variations_saved', function() { - $( '#_subscription_one_time_shipping' ).addClass( 'wcs_ots_needs_update' ); - }); - - // After variations have been loaded and if the One Time Shipping field needs updating, check if One Time Shipping is still available - $( '#woocommerce-product-data' ).on( 'woocommerce_variations_loaded', function() { - if ( $( '.wcs_ots_needs_update' ).length ) { - $.disableEnableOneTimeShipping(); - } - }); - - // After variations have been loaded, check which ones are tied to subscriptions to prevent them from being deleted. - $( '#woocommerce-product-data' ).on( 'woocommerce_variations_loaded', function() { - $.maybeDisableRemoveLinks(); - } ); - - // Triggered by $.disableEnableOneTimeShipping() after One Time shipping has been enabled or disabled for variations. - // If the One Time Shipping field needs updating, send the ajax request to update the product setting in the backend - $( '#_subscription_one_time_shipping' ).on( 'subscription_one_time_shipping_updated', function( event, is_synced_or_has_trial ) { - - if ( $( '.wcs_ots_needs_update' ).length ) { - var data = { - action: 'wcs_update_one_time_shipping', - product_id: woocommerce_admin_meta_boxes_variations.post_id, - one_time_shipping_enabled: ! is_synced_or_has_trial, - one_time_shipping_selected: $( '#_subscription_one_time_shipping' ).prop( 'checked' ), - nonce: WCSubscriptions.oneTimeShippingCheckNonce, - }; - - $.ajax({ - url: WCSubscriptions.ajaxUrl, - data: data, - type: 'POST', - success : function( response ) { - // remove the flag requiring the one time shipping field to be updated - $( '#_subscription_one_time_shipping' ).removeClass( 'wcs_ots_needs_update' ); - $( '#_subscription_one_time_shipping' ).prop( 'checked', response.one_time_shipping == 'yes' ? true : false ); - } - }); - } - }); - - $( '#general_product_data, #variable_product_options' ).on( 'change', '[class^="wc_input_subscription_payment_sync"], [class^="wc_input_subscription_trial_length"]', function() { - $.disableEnableOneTimeShipping(); - }); - - /** - * Prevents removal of variations in use by a subscription. - */ - var wcs_prevent_variation_removal = { - init: function() { - if ( 0 === $( '#woocommerce-product-data' ).length ) { - return; - } - - $( 'body' ).on( 'woocommerce-product-type-change', this.product_type_change ); - $( '#variable_product_options' ).on( 'reload', this.product_type_change ); - $( 'select.variation_actions' ).on( 'delete_all_no_subscriptions_ajax_data', this.bulk_action_data ); - this.product_type_change(); - }, - - product_type_change: function() { - var product_type = $( '#product-type' ).val(); - var $variation_actions = $( 'select.variation_actions' ); - var $delete_all = $variation_actions.find( 'option[value="delete_all"], option[value="delete_all_no_subscriptions"]' ); - - if ( 'variable-subscription' === product_type && 'delete_all' === $delete_all.val() ) { - $delete_all.data( 'wcs_original_wc_label', $delete_all.text() ) - .attr( 'value', 'delete_all_no_subscriptions' ) - .text( WCSubscriptions.bulkDeleteOptionLabel ); - } else if ( 'variable-subscription' !== product_type && 'delete_all_no_subscriptions' === $delete_all.val() ) { - $delete_all.text( $delete_all.data( 'wcs_original_wc_label' ) ) - .attr( 'value', 'delete_all' ); - } - }, - - bulk_action_data: function( event, data ) { - if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_delete_all_variations ) ) { - if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_last_warning ) ) { - data.allowed = true; - - // do_variation_action() in woocommerce/assets/js/admin/meta-boxes-product-variation.js doesn't - // allow us to do anything after the AJAX request, so we need to listen to all AJAX requests for a - // little while to update the quantity and refresh the variation list. - $( document ).bind( 'ajaxComplete', wcs_prevent_variation_removal.update_qty_after_removal ); - } - } - - return data; - }, - - update_qty_after_removal: function( event, jqXHR, ajaxOptions ) { - var $variations = $( '#variable_product_options .woocommerce_variations' ); - var removed; - - // Not our bulk edit request. Ignore. - if ( -1 === ajaxOptions.data.indexOf( 'action=woocommerce_bulk_edit_variations' ) || -1 === ajaxOptions.data.indexOf( 'bulk_action=delete_all_no_subscriptions' ) ) { - return; - } - - // Unbind so this doesn't get called every time an AJAX request is performed. - $( document ).unbind( 'ajaxComplete', wcs_prevent_variation_removal.update_qty_after_removal ); - - // Update variation quantity. - removed = ( 'OK' === jqXHR.statusText ) ? parseInt( jqXHR.responseText, 10 ) : 0; - $variations.attr( 'data-total', Math.max( 0, parseInt( $variations.attr( 'data-total' ), 10 ) - removed ) ); - $( '#variable_product_options' ).trigger( 'reload' ); - }, - }; - wcs_prevent_variation_removal.init(); - - /* - * Prevents changing of the product type for subscription products in use by a subscription. - */ - var wcs_prevent_product_type_change = { - init: function() { - if ( 'yes' !== WCSubscriptions.productHasSubscriptions ) { - return; - } - - var $select = $( 'select#product-type' ); - var $options = $select.find( 'option' ); - var $selection = $options.filter( 'option:selected' ); - - if ( 'subscription' !== $selection.val() && 'variable-subscription' !== $selection.val() ) { - return; - } - - $options.not( $selection ).prop( 'disabled', true ); - $select.addClass( 'tips' ).attr( 'data-tip', WCSubscriptions.productTypeWarning ); - }, - }; - wcs_prevent_product_type_change.init(); - - /* - * Handles enabling and disabling PayPal Standard for Subscriptions. - */ - var wcs_paypal_standard_settings = { - - init: function() { - if ( 0 === $( '#woocommerce_paypal_enabled' ).length ) { - return; - } - - $( '#woocommerce_paypal_enabled' ).on( 'change', this.paypal_enabled_change ); - $( '#woocommerce_paypal_enabled_for_subscriptions' ).on( 'change', this.paypal_for_subscriptions_enabled ); - this.paypal_enabled_change(); - }, - - /** - * Show and hide the enable PayPal for Subscriptions checkbox when PayPal is enabled or disabled. - */ - paypal_enabled_change: function() { - var $enabled_for_subscriptions_element = $( '#woocommerce_paypal_enabled_for_subscriptions' ).closest( 'tr' ); - - if ( $( '#woocommerce_paypal_enabled' ).is( ':checked' ) ) { - $enabled_for_subscriptions_element.show(); - } else { - $enabled_for_subscriptions_element.hide(); - } - }, - - /** - * Display a confirm dialog when PayPal for Subscriptions is enabled (checked). - */ - paypal_for_subscriptions_enabled: function() { - if ( $( this ).is( ':checked' ) && ! confirm( WCSubscriptions.enablePayPalWarning ) ) { - $( this ).removeAttr( 'checked' ); - } - } - }; - wcs_paypal_standard_settings.init(); - -}); diff --git a/assets/js/admin/meta-boxes-subscription.js b/assets/js/admin/meta-boxes-subscription.js deleted file mode 100644 index 4e9d919..0000000 --- a/assets/js/admin/meta-boxes-subscription.js +++ /dev/null @@ -1,239 +0,0 @@ -jQuery(document).ready(function($){ - var timezone = jstz.determine(); - - // Display the timezone for date changes - $( '#wcs-timezone' ).text( timezone.name() ); - - // Display times in client's timezone (based on UTC) - $( '.woocommerce-subscriptions.date-picker' ).each(function(){ - var $date_input = $(this), - date_type = $date_input.attr( 'id' ), - $hour_input = $( '#'+date_type+'_hour' ), - $minute_input = $( '#'+date_type+'_minute' ), - time = $('#'+date_type+'_timestamp_utc').val(), - date = moment.unix(time); - - if ( time > 0 ) { - date.local(); - $date_input.val( date.year() + '-' + ( zeroise( date.months() + 1 ) ) + '-' + ( date.format( 'DD' ) ) ); - $hour_input.val( date.format( 'HH' ) ); - $minute_input.val( date.format( 'mm' ) ); - } - }); - - // Make sure start date picker is in the past - $( '.woocommerce-subscriptions.date-picker#start' ).datepicker( 'option','maxDate',moment().toDate()); - - // Make sure other date pickers are in the future - $( '.woocommerce-subscriptions.date-picker:not(#start)' ).datepicker( 'option','minDate',moment().add(1,'hours').toDate()); - - // Validate date when hour/minute inputs change - $( '[name$="_hour"], [name$="_minute"]' ).on( 'change', function() { - $( '#' + $(this).attr( 'name' ).replace( '_hour', '' ).replace( '_minute', '' ) ).change(); - }); - - // Validate entire date - $( '.woocommerce-subscriptions.date-picker' ).on( 'change',function(){ - - // The date was deleted, clear hour/minute inputs values and set the UTC timestamp to 0 - if( '' == $(this).val() ) { - $( '#' + $(this).attr( 'id' ) + '_hour' ).val(''); - $( '#' + $(this).attr( 'id' ) + '_minute' ).val(''); - $( '#' + $(this).attr( 'id' ) + '_timestamp_utc' ).val(0); - return; - } - - var time_now = moment(), - one_hour_from_now = moment().add(1,'hours' ), - $date_input = $(this), - date_type = $date_input.attr( 'id' ), - date_pieces = $date_input.val().split( '-' ), - $hour_input = $( '#'+date_type+'_hour' ), - $minute_input = $( '#'+date_type+'_minute' ), - chosen_hour = (0 == $hour_input.val().length) ? one_hour_from_now.format( 'HH' ) : $hour_input.val(), - chosen_minute = (0 == $minute_input.val().length) ? one_hour_from_now.format( 'mm' ) : $minute_input.val(), - chosen_date = moment({ - years: date_pieces[0], - months: (date_pieces[1] - 1), - date: (date_pieces[2]), - hours: chosen_hour, - minutes: chosen_minute, - seconds: one_hour_from_now.format( 'ss' ) - }); - - // Make sure start date is before now. - if ( 'start' == date_type ) { - - if ( false === chosen_date.isBefore( time_now ) ) { - alert( wcs_admin_meta_boxes.i18n_start_date_notice ); - $date_input.val( time_now.year() + '-' + ( zeroise( time_now.months() + 1 ) ) + '-' + ( time_now.format( 'DD' ) ) ); - $hour_input.val( time_now.format( 'HH' ) ); - $minute_input.val( time_now.format( 'mm' ) ); - } - - } - - // Make sure trial end and next payment are after start date - if ( ( 'trial_end' == date_type || 'next_payment' == date_type ) && '' != $( '#start_timestamp_utc' ).val() ) { - var change_date = false, - start = moment.unix( $('#start_timestamp_utc').val() ); - - // Make sure trial end is after start date - if ( 'trial_end' == date_type && chosen_date.isBefore( start, 'minute' ) ) { - - if ( 'trial_end' == date_type ) { - alert( wcs_admin_meta_boxes.i18n_trial_end_start_notice ); - } else if ( 'next_payment' == date_type ) { - alert( wcs_admin_meta_boxes.i18n_next_payment_start_notice ); - } - - // Change the date - $date_input.val( start.year() + '-' + ( zeroise( start.months() + 1 ) ) + '-' + ( start.format( 'DD' ) ) ); - $hour_input.val( start.format( 'HH' ) ); - $minute_input.val( start.format( 'mm' ) ); - } - } - - // Make sure next payment is after trial end - if ( 'next_payment' == date_type && '' != $( '#trial_end_timestamp_utc' ).val() ) { - var trial_end = moment.unix( $('#trial_end_timestamp_utc').val() ); - - if ( chosen_date.isBefore( trial_end, 'minute' ) ) { - alert( wcs_admin_meta_boxes.i18n_next_payment_trial_notice ); - $date_input.val( trial_end.year() + '-' + ( zeroise( trial_end.months() + 1 ) ) + '-' + ( trial_end.format( 'DD' ) ) ); - $hour_input.val( trial_end.format( 'HH' ) ); - $minute_input.val( trial_end.format( 'mm' ) ); - } - } - - // Make sure trial end is before next payment and expiration is after next payment date - else if ( ( 'trial_end' == date_type || 'end' == date_type ) && '' != $( '#next_payment' ).val() ) { - var change_date = false, - next_payment = moment.unix( $('#next_payment_timestamp_utc').val() ); - - // Make sure trial end is before or equal to next payment - if ( 'trial_end' == date_type && next_payment.isBefore( chosen_date, 'minute' ) ) { - alert( wcs_admin_meta_boxes.i18n_trial_end_next_notice ); - change_date = true; - } - // Make sure end date is after next payment date - else if ( 'end' == date_type && chosen_date.isBefore( next_payment, 'minute' ) ) { - alert( wcs_admin_meta_boxes.i18n_end_date_notice ); - change_date = true; - } - - if ( true === change_date ) { - $date_input.val( next_payment.year() + '-' + ( zeroise( next_payment.months() + 1 ) ) + '-' + ( next_payment.format( 'DD' ) ) ); - $hour_input.val( next_payment.format( 'HH' ) ); - $minute_input.val( next_payment.format( 'mm' ) ); - } - } - - // Make sure the date is more than an hour in the future - if ( 'trial_end' != date_type && 'start' != date_type && chosen_date.unix() < one_hour_from_now.unix() ) { - - alert( wcs_admin_meta_boxes.i18n_past_date_notice ); - - // Set date to current day - $date_input.val( one_hour_from_now.year() + '-' + ( zeroise( one_hour_from_now.months() + 1 ) ) + '-' + ( one_hour_from_now.format( 'DD' ) ) ); - - // Set time if current time is in the past - if ( chosen_date.hours() < one_hour_from_now.hours() || ( chosen_date.hours() == one_hour_from_now.hours() && chosen_date.minutes() < one_hour_from_now.minutes() ) ) { - $hour_input.val( one_hour_from_now.format( 'HH' ) ); - $minute_input.val( one_hour_from_now.format( 'mm' ) ); - } - } - - if( 0 == $hour_input.val().length ){ - $hour_input.val(one_hour_from_now.format( 'HH' )); - } - - if( 0 == $minute_input.val().length ){ - $minute_input.val(one_hour_from_now.format( 'mm' )); - } - - // Update the UTC timestamp sent to the server - date_pieces = $date_input.val().split( '-' ); - - $('#'+date_type+'_timestamp_utc').val(moment({ - years: date_pieces[0], - months: (date_pieces[1] - 1), - date: (date_pieces[2]), - hours: $hour_input.val(), - minutes: $minute_input.val(), - seconds: one_hour_from_now.format( 'ss' ) - }).utc().unix()); - - $( 'body' ).trigger( 'wcs-updated-date',date_type); - }); - - function zeroise( val ) { - return (val > 9 ) ? val : '0' + val; - } - - if( $( '#parent-order-id' ).is( 'select' ) ) { - wcs_update_parent_order_options(); - - $( '#customer_user' ).on( 'change', wcs_update_parent_order_options ); - } - - function wcs_update_parent_order_options() { - - // Get user ID to load orders for - var user_id = $( '#customer_user' ).val(); - - if ( ! user_id ) { - return false; - } - - var data = { - user_id: user_id, - action: 'wcs_get_customer_orders', - security: wcs_admin_meta_boxes.get_customer_orders_nonce - }; - - $( '#parent-order-id' ).siblings( '.select2-container' ).block({ - message: null, - overlayCSS: { - background: '#fff', - opacity: 0.6 - } - }); - - $.ajax({ - url: WCSubscriptions.ajaxUrl, - data: data, - type: 'POST', - success: function( response ) { - if ( response ) { - var $orderlist = $( '#parent-order-id' ); - - $( '#parent-order-id' ).select2( 'val', '' ); - - $orderlist.empty(); // remove old options - - $orderlist.append( $( '' ).attr( 'value', '' ).text( 'Select an order' ) ); - - $.each( response, function( order_id, order_number ) { - $orderlist.append( $( '' ).attr( 'value', order_id ).text( order_number ) ); - }); - - $( '#parent-order-id' ).siblings( '.select2-container' ).unblock(); - } - } - }); - return false; - }; - - $('body.post-type-shop_subscription #post').submit(function(){ - if('wcs_process_renewal' == $( "body.post-type-shop_subscription select[name='wc_order_action']" ).val()) { - return confirm(wcs_admin_meta_boxes.process_renewal_action_warning); - } - }); - - $('body.post-type-shop_subscription #post').submit(function(){ - if ( typeof wcs_admin_meta_boxes.change_payment_method_warning != 'undefined' && wcs_admin_meta_boxes.payment_method != $('#_payment_method').val() ) { - return confirm(wcs_admin_meta_boxes.change_payment_method_warning); - } - }); -}); diff --git a/assets/js/admin/reports.js b/assets/js/admin/reports.js index 418e592..5866702 100644 --- a/assets/js/admin/reports.js +++ b/assets/js/admin/reports.js @@ -1,4 +1,4 @@ -jQuery(function($) { +jQuery( function( $ ) { $.extend({ wcs_format_money: function(value,decimal_precision) { diff --git a/assets/js/admin/wcs-meta-boxes-order.js b/assets/js/admin/wcs-meta-boxes-order.js deleted file mode 100644 index c99b87b..0000000 --- a/assets/js/admin/wcs-meta-boxes-order.js +++ /dev/null @@ -1,8 +0,0 @@ -jQuery(document).ready(function($){ - - $('body.post-type-shop_order #post').submit(function(){ - if('wcs_retry_renewal_payment' == $( "body.post-type-shop_order select[name='wc_order_action']" ).val()) { - return confirm(wcs_admin_order_meta_boxes.retry_renewal_payment_action_warning); - } - }); -}); diff --git a/assets/js/wcs-upgrade.js b/assets/js/wcs-upgrade.js deleted file mode 100644 index 1ee2b8d..0000000 --- a/assets/js/wcs-upgrade.js +++ /dev/null @@ -1,206 +0,0 @@ -jQuery(document).ready(function($){ - var upgrade_start_time = null, - total_subscriptions = wcs_update_script_data.subscription_count; - - $('#update-messages').slideUp(); - $('#upgrade-step-3').slideUp(); - - $('form#subscriptions-upgrade').on('submit',function(e){ - $('#update-welcome').slideUp(600); - $('#update-messages').slideDown(600); - if('true'==wcs_update_script_data.really_old_version){ - wcs_ajax_update_really_old_version(); - } else if('true'==wcs_update_script_data.upgrade_to_1_5){ - wcs_ajax_update_products(); - wcs_ajax_update_hooks(); - } else if('true'==wcs_update_script_data.upgrade_to_2_0){ - wcs_ajax_update_subscriptions(); - } else if('true'==wcs_update_script_data.repair_2_0){ - wcs_ajax_repair_subscriptions(); - } else { - wcs_ajax_update_complete(); - } - e.preventDefault(); - }); - function wcs_ajax_update_really_old_version(){ - $.ajax({ - url: wcs_update_script_data.ajax_url, - type: 'POST', - data: { - action: 'wcs_upgrade', - upgrade_step: 'really_old_version', - nonce: wcs_update_script_data.upgrade_nonce - }, - success: function(results) { - $('#update-messages ol').append($('
  • ').text(results.message)); - wcs_ajax_update_products(); - wcs_ajax_update_hooks(); - }, - error: function(results,status,errorThrown){ - wcs_ajax_update_error(); - } - }); - } - function wcs_ajax_update_products(){ - $.ajax({ - url: wcs_update_script_data.ajax_url, - type: 'POST', - data: { - action: 'wcs_upgrade', - upgrade_step: 'products', - nonce: wcs_update_script_data.upgrade_nonce - }, - success: function(results) { - $('#update-messages ol').append($('
  • ').text(results.message)); - }, - error: function(results,status,errorThrown){ - wcs_ajax_update_error(); - } - }); - } - function wcs_ajax_update_hooks() { - var start_time = new Date(); - $.ajax({ - url: wcs_update_script_data.ajax_url, - type: 'POST', - data: { - action: 'wcs_upgrade', - upgrade_step: 'hooks', - nonce: wcs_update_script_data.upgrade_nonce - }, - success: function(results) { - if(results.message){ - var end_time = new Date(), - execution_time = Math.ceil( ( end_time.getTime() - start_time.getTime() ) / 1000 ); - $('#update-messages ol').append($('
  • ').text(results.message.replace('{execution_time}',execution_time))); - } - if( undefined == typeof(results.upgraded_count) || parseInt(results.upgraded_count) <= ( wcs_update_script_data.hooks_per_request - 1 ) ){ - wcs_ajax_update_subscriptions(); - } else { - wcs_ajax_update_hooks(); - } - }, - error: function(results,status,errorThrown){ - wcs_ajax_update_error(); - } - }); - } - function wcs_ajax_update_subscriptions() { - var start_time = new Date(); - - if ( null === upgrade_start_time ) { - upgrade_start_time = start_time; - } - - $.ajax({ - url: wcs_update_script_data.ajax_url, - type: 'POST', - data: { - action: 'wcs_upgrade', - upgrade_step: 'subscriptions', - nonce: wcs_update_script_data.upgrade_nonce - }, - success: function(results) { - if('success'==results.status){ - var end_time = new Date(), - execution_time = Math.ceil( ( end_time.getTime() - start_time.getTime() ) / 1000 ); - - $('#update-messages ol').append($('
  • ').text(results.message.replace('{execution_time}',execution_time))); - - wcs_update_script_data.subscription_count -= results.upgraded_count; - - if( "undefined" === typeof(results.upgraded_count) || parseInt(wcs_update_script_data.subscription_count) <= 0 ) { - wcs_ajax_update_complete(); - } else { - wcs_ajax_update_estimated_time(results.time_message); - wcs_ajax_update_subscriptions(); - } - } else { - wcs_ajax_update_error(results.message); - } - }, - error: function(results,status,errorThrown){ - $('
    Error: ' + results.status + ' ' + errorThrown + '').appendTo('#update-error p'); - wcs_ajax_update_error( $('#update-error p').html() ); - } - }); - } - function wcs_ajax_repair_subscriptions() { - var start_time = new Date(); - - if ( null === upgrade_start_time ) { - upgrade_start_time = start_time; - } - - $.ajax({ - url: wcs_update_script_data.ajax_url, - type: 'POST', - data: { - action: 'wcs_upgrade', - upgrade_step: 'subscription_dates_repair', - nonce: wcs_update_script_data.upgrade_nonce - }, - success: function(results) { - if('success'==results.status){ - var end_time = new Date(), - execution_time = Math.ceil( ( end_time.getTime() - start_time.getTime() ) / 1000 ); - - $('#update-messages ol').append($('
  • ').text(results.message.replace('{execution_time}',execution_time))); - - wcs_update_script_data.subscription_count -= results.repaired_count; - wcs_update_script_data.subscription_count -= results.unrepaired_count; - - if( parseInt(wcs_update_script_data.subscription_count) <= 0 ) { - wcs_ajax_update_complete(); - } else { - wcs_ajax_update_estimated_time(results.time_message); - wcs_ajax_repair_subscriptions(); - } - } else { - wcs_ajax_update_error(results.message); - } - }, - error: function(results,status,errorThrown){ - $('
    Error: ' + results.status + ' ' + errorThrown + '').appendTo('#update-error p'); - wcs_ajax_update_error( $('#update-error p').html() ); - } - }); - } - function wcs_ajax_update_complete() { - $('#update-ajax-loader, #estimated_time').slideUp(function(){ - $('#update-complete').slideDown(); - }); - } - function wcs_ajax_update_error(message) { - message = message || ''; - if ( message.length > 0 ){ - $('#update-error p').html(message); - } - $('#update-ajax-loader, #estimated_time').slideUp(function(){ - $('#update-error').slideDown(); - }); - } - function wcs_ajax_update_estimated_time(message) { - var total_updated = total_subscriptions - wcs_update_script_data.subscription_count, - now = new Date(), - execution_time, - time_per_update, - time_left, - time_left_minutes, - time_left_seconds; - - execution_time = Math.ceil( ( now.getTime() - upgrade_start_time.getTime() ) / 1000 ); - time_per_update = execution_time / total_updated; - - time_left = Math.floor( wcs_update_script_data.subscription_count * time_per_update ); - time_left_minutes = Math.floor( time_left / 60 ); - time_left_seconds = time_left % 60; - - $('#estimated_time').html(message.replace( '{time_left}', time_left_minutes + ":" + zeropad(time_left_seconds) )); - } - function zeropad(number) { - var pad_char = 0, - pad = new Array(3).join(pad_char); - return (pad + number).slice(-pad.length); - } -}); \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 74e2ccc..6f271cb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,207 @@ *** WooCommerce Subscriptions Changelog *** +2022-10-11 - version 4.6.0 +* Add: Declare incompatibility with WooCommerce High-Performance Order Storage (HPOS). +* Fix: Move One Time Shipping metabox fields to use the woocommerce_product_options_shipping_product_data hook introduced in WC 6.0. +* Update: Improve handling of bulk action execution. +* Dev: Update subscriptions-core to 2.3.0 + +2022-08-26 - version 4.5.1 +* Fix - Fatal Error caused in rare cases where quantity is zero during renewal, builds upon fix released in 4.4.0. + +2022-08-04 - version 4.5.0 +* Dev: Add missing `woocommerce_subscriptions_switch_link_text` and `woocommerce_subscriptions_switch_link_classes` filters for finer control of switch link. PR#4382 +* Fix: Update subscription address when changed with renewals on block checkout. + +2022-06-07 - version 4.4.0 +* Fix - Fatal Error caused in rare cases where quantity is zero during renewal. + +2022-05-24 - version 4.3.0 +* Dev: Retrieving users subscriptions order has been updated to use the WooCommerce specific APIs in WC_Subscriptions_Order. +* Dev: Deprecate the WC_Subscriptions_Order::get_meta() function. Use wcs_get_objects_property( $order, $meta_key, "single", $default ) instead. +* Dev: Update the wcs_get_objects_property() function to prevent calls to get_post_meta() on objects that support calling the get_meta() function. +* Dev: Replace the get_post_meta() calls in WCS_Post_Meta_Cache_Manager with WC_Order::get_meta(). +* Dev: Replace code using get_post_type( $order_id ) with WC Data Store get_order_type(). +* Dev: Replace all cases of update_post_meta() where an Order ID is passed to use WC_Order::update_meta_data() instead. + +2022-04-29 - version 4.2.0 +* Fix: Remove WooThemes helper/updater admin notice/banner. PR#4328 +* Fix: Remove PHP/deprecation notices during the early renewal and switch process when using WooCommerce Blocks 7.2. PR#4341 +* Fix: Display subscription billing details in the Cart Block when purchasing products with subscription plans created using the All Products extension. subscriptions-core#149 +* Update: Switch to global functions to remove deprecation warnings originating from WooCommerce Blocks. subscriptions-core#124 +* Dev: Update subscriptions-core to 1.9.0. PR#4345 + +2022-03-22 - version 4.1.0 +* Fix: Undefined variable `user_can_suspend` when a customer suspension limit is defined and the max number of suspensions has been reached. PR#4318 +* Fix: Sets up subscriptions integration with the Mini Cart Block and adds new hook to filter compatible blocks. subscriptions-core#103 +* Fix: When using a WooCommerce Blocks powered checkout, fix an issue that led to limited products being removed from the cart when completing a switch or renewal order. subscriptions-core#119 +* Fix: When there is only one Shipping Method available in the recurring shipping package, make sure that this method is treated as selected in the current session and the `woocommerce_after_shipping_rate` action runs. subscriptions-core#115 +* Fix: Don't anonymize new subscriptions related to old subscriptions via a resubscribe relationship. subscriptions-core#121 +* Fix: Content that appears on the My account > Payment methods page should be translatable. subscriptions-core#125 +* Dev: Update subscriptions-core to 1.7.0. PR#4319 + +2022-02-07 - version 4.0.2 +* Dev: Update subscriptions-core to 1.6.3. PR#4307 +* Fix: Replace uses of is_ajax() with wp_doing_ajax(). wcs#4296 PR#4307 +* Improve handling of session data. + +2022-01-19 - version 4.0.1 +* Fix: Prevent fatal error when too few arguments passed to widget_title filter. PR#4302 +* Dev: Update subscriptions-core to 1.6.2. PR#4302 + +2022-01-19 - version 4.0.0 +* New: Update the minimum required WooCommerce version from 3.9 to 4.4. PR#4282 +* Fix: Unable to remove subscription line items via the REST API. PR#4258 +* Fix: Don't show subscription related product fields when the custom variable type products are created. PR#4215 +* Fix: Add consistent margins to the recurring taxes totals row on the Checkout and Cart block. PR#4273 +* Fix: Fatal error due to order with no created date in order row template. PR#4273 +* Fix: Fatal error on the customer payment page for renewal orders with deleted products. PR#4273 +* Fix: Prevent fatal errors on the admin subscriptions screen when a subscription fails to load. PR#4290 +* Fix: Incorrect message on the subscriptions table when filtering returns no results. PR#4290 +* Fix: Update Cart and Checkout Block hooks to prevent deprecation warnings. PR#4280 +* Tweak: Update tooltip wording when deleting product variation. PR#4273 +* Tweak: Don't show an admin error notice when a store downgrades to a previous minor version of Subscriptions. PR#4273 +* Tweak: Misleading order note on payment method change. PR#4273 +* Dev: Moved subscription core files moved into a new subscriptions-core library (loaded from vendor/woocommerce/subscriptions-core). PR#4121 +* Dev: New `WC_Subscriptions_Plugin` class to be the main Subscriptions plugin handler class. PR#4116 +* Dev: Moved and deprecated 33 functions from class `WC_Subscriptions` to more suitable classes. PR#4114 +* Dev: Moved switching feature related classes into its own directory (`includes/switching/`). PR#4122 +* Dev: Moved payment retry feature related classes into its own directory (`includes/payment-retry/`). PR#4146 +* Dev: Moved early renewal feature related classes into its own directory (`includes/early-renewals/`). PR#4148 +* Dev: Moved the "Accept manual renewals" feature and settings to a new `WCS_Manual_Renewal_Manager` class. PR#4124 +* Dev: Moved the "Customer Suspensions" feature and settings code to a new `WCS_Customer_Suspension_Manager` class. PR#4138 +* Dev: Moved the "Drip Downloadable Content" feature and settings to a new `WCS_Drip_Downloads_Manager` class. PR#4142 +* Dev: Moved the "Allow $0 initial checkout without a payment method" feature and settings to a new `WCS_Zero_Initial_Payment_Checkout_Manager` class. PR#4145 +* Dev: Moved the "Limited payment recurring coupon" feature to a new `WCS_Limited_Recurring_Coupon_Manager` class. PR#4150 +* Dev: Moved the custom subscription product and checkout button text feature to a new `WCS_Call_To_Action_Button_Text_Manager` class. PR#4152 +* Dev: Moved the custom active and inactive subscriber roles feature to a new `WCS_Subscriber_Role_Manager` class. PR#4153 +* Dev: Removed the Action Scheduler library from WC Subscriptions since it has been included in WooCommerce core since version 3.0. PR#4202 + +2021-10-06 - version 3.1.6 +* Fix: Add back the limited subscription setting for simple subscription products (introduced in v3.1.5). PR#4214 + +2021-09-28 - version 3.1.5 +* Fix: Update subtracted tax amounts to account for quantity changes. PR#4107 +* Fix: Correctly remove limited coupons (i.e. "Active for x payments") when the coupon code is made up of only numeric characters. PR#4139 +* Fix: Only set subtracted taxes on new items when the rates don't match the base location. PR#4177 +* Fix: Hide variable subscription meta fields on the Edit Product page of custom variable products. PR#4193 +* Fix: Use the shipping fields to get and save the edit subscription shipping field data. PR#4161 +* Fix: Fix TypeError exceptions by checking for WC_Order types inside wcs_get_subscriptions_for_order(). PR#4188 +* Fix: Incorrect subtracted tax calculations when updating the subscription when the store currency uses a comma decimal separator. PR#4182 +* Fix: Hide the shipping address fields on checkout when the cart contains a subscription product and the 'Force shipping to billing address' setting is selected. PR#4172 +* Fix: Get the signup fee for coupon calculation inclusive or excluding tax depending on store settings. PR#4166 + +2021-07-22 - version 3.1.4 +* Fix: Points and Rewards discounts (including WC Coupons when Points and Rewards is active) being removed from the cart when applied on the checkout page. PR#4158 +* Fix: Subscriptions with one-time shipping having shipping charged on all renewal orders. PR#4156 +* Fix: Rare fatal error caused by missing WC_Query class. PR#4155 +* Fix: Make loading the variation edit product tab more performant on large sites. PR#4144 +* Fix: Add a primary key to the last payment temporary table to improve compatibility with some hosts on larger sites. PR#4151 +* Tweak: Update the wording when a customer edits their subscription address that this applies to "future renewals". PR#4118 +* Dev: Add missing `woocommerce_rest_pre_insert_shop_subscription_object` filter to prepare_object_for_database() within the Subscriptions REST API controller class. PR#4119 +* Dev: Add a `data-payment-method` attribute to the Early Renewal modal button action. PR#4123 + +2021-06-09 - version 3.1.3 +* Fix: Switch calculations not correctly charging the full sign up fee when the "Prorate Sign up Fee" option is set to "Never (charge the full sign up fee)". PR#4096 +* Fix: Fixes PayPal Reference Transactions integration with Checkout blocks. PR#4105 +* Fix: Set the updated payment token on all pending-payment renewals so that manually retrying a failed payment uses the updated token set on the subscription. PR#4108 +* Dev: Moved the `WC_Subscriptions::enqueue_scripts` and` WC_Subscriptions::equeue_styles` static functions to the new `WC_Subscriptions_Frontend_Scripts` class (deprecated existing functions). PR#4104 + +2021-05-19 - version 3.1.2 +* Fix: Don't show recurring shipping method selection when the rates and options match the initial cart options. PR#4091 +* Fix: Update the recurring shipping totals on selection and fix invalid recurring shipping method notices. PR#4099 +* Fix: Update the subscription shipping address after on switch. PR#4095 + +2021-05-12 - version 3.1.1 +* Fix: "Invalid recurring shipping method" error on checkout when attempting to purchase a subscription with one-time shipping. PR#4088 +* Fix: Rework subscription webhook migration script added in 3.1 to clear cached webhook data. PR#4082 + +2021-05-10 - version 3.1.0 +* New: Add support for WooCommerce Cart and Checkout blocks. PR#3993 +* New: Support v3 subscription endpoints. PR#4001 +* New: Add woocommerce_inbox_variant option. PR#4084 +* New: Update the WC minimum required version to WC 3.7. PR#3914 +* New: Add a new Accounts setting to allow admin to enable registration on checkout of subscription customers. PR#3883 +* New: Display switch, renewal and resubscribe context in the 'Add to cart' and 'Place order' buttons. PR#3624 +* Fix: Fix customer subscription caching errors on multisite installations. PR#4074 +* Fix: Update the `_subtracted_base_location_taxes` when an admin edits the subscription line item subtotal. PR#4068 +* Fix: Migrate existing v3 subscription webhooks to v1 when upgrading to 3.1 to maintain the same payload delivered. PR#4079 +* Fix: Fatal error when processing an initial PayPal Standard payment on a manually created subscription that has no parent order. PR#4033 +* Fix: Only allow reactivation of pending-canceled subscription when end date is in the future. PR#4037 +* Fix: Don't add a free trial period when resubscribing to a synced subscription. PR#4045 +* Fix: Catch exceptions thrown when updating a subscription's payment method. PR#4051 +* Fix: Incorrect sign-up fee discount amount calculated when the customer is outside of all tax zones and prices are entered with tax included. PR#4052 +* Fix: Allow paying for pending parent orders that contain a limited subscription product where the subscription is already active. PR#4061 +* Fix: Show recurring shipping totals/options when a virtual product is the last product added to the cart. PR#4053 +* Fix: Refactor how `_subtracted_base_location_tax` order item meta is stored on subscription items to avoid calculation issues when the quantity is changed. PR#4062 +* Fix: Fixes PHP notices when using the v1/subscriptions/ID/orders REST endpoint on a subscription where one of its related orders was directly deleted from the database. PR#4058 +* Tweak: Always show the delete save card button but now display a notice when trying to delete a card tied to an active subscription. PR#4076 +* Tweak: Update the subscription order note to when the PayPal Standard subscription is suspended and migrated over to PayPal Reference Transactions during a switch request. PR#4057 +* Tweak: Display orders in the related orders admin table sorted by date. PR#3575 +* Dev: Refactor the recurring totals template. PR#3550 + +2021-04-16 - version 3.0.15 +* Tweak: Improve compatibility with WPML. PR#4034 +* Dev: Introduce filter to allow third-parties gateways to filter whether a token meta was updated. PR#4030 +* Fix: Fixes for endpoint in "My Account". + +2021-04-07 - version 3.0.14 +* New: Add support for importing and exporting subscription variations via the WooCommerce > Products > Export/Import tools. PR#3970 +* Fix: Only show one Subscriptions settings menu item on the WC Admin navigation. PR#4054 +* Fix: Prevent PHP notices on the Edit Subscription page caused accessing an undefined index. PR#4056 +* Fix: Existing variations will no longer be deleted when updating a regular variable product to a subscription variable product. PR#3795 +* Fix: Update the `_subtracted_base_location_tax` meta data when a subscription's line item quantity is modified. PR#4039 +* Fix: Next payment date calculations when the start date and last payment date are the same. PR#4017 +* Dev: Update jQuery 3.0 deprecations. PR#4015 + +2021-02-16 - version 3.0.13 +* Fix: Pass an order status array to get_order_report_data() to prevent possible fatals by 3rd parties. PR#3930 +* Fix: Change logic to allow customers to pay for failed order with limited product. PR#3947 +* Fix: Prevent base length from being saved in the DB when retrieved in 'apportion_length'. PR#3954 +* Fix: Prevent errors when using Product Bundles (which uses WCS_Add_Cart_Item) by introducing a WCS_Add_Cart_Item::is_switch_after_fully_reduced_prepaid_term() function. PR#3957 +* Fix: Introduce an SQL Transactions helper with automatic commit/rollback on shutdown. Prevents strange behaviour when a shutdown occurs during a SQL transaction. PR#3827 +* Fix: [PHP 8.0] Change maybe_retry_payment() arg name to prevent unknown variable name errors. PR#3984 +* Fix: Delete '_switch_totals_calc_base_length' meta incorrectly saved in the database on upgrade. PR#3958 +* Fix: Prevent WC_Order_Item_Coupon::offsetGet errors during renewal. PR#4009 +* Dev: Introduce new hooks to various Switch_Totals_Calculator functions. PR#3872 + +2021-01-06 - version 3.0.12 +* New: Add an order note when subscriptions are deleted after the customer is deleted. PR#3783 +* New: [WC Admin] Register items in new navigation menu. PR#3868 +* New: [WC Admin] Add the Subscriptions setting to WC Admin's Settings navigation list. PR#3911 +* Tweak: Fix capitalisation of Subscription webhook topic names so they match WooCommerce core. PR#3902 +* Tweak: Refactor `wcs_help_tip()` to enable custom tooltip classes. PR#3871 +* Tweak: Replace remaining uses of new WC_Order() with wc_get_order() to get an order instance. PR#3858 +* Fix: Fix the amount customers are charged after switching after a previous switch which reduced the pre-paid term fully. PR#3805 +* Fix: Calculate a gap payment when switching to a subscription with one length and no payment date to extend. PR#3879 +* Fix: Only require cart payment if there's a subscription with a next payment date. PR#3899 +* Fix: Only display the failed scheduled action warning to admin users who can view subscriptions. PR#3905 +* Fix: Prefix attribute keys correctly before getting switch url. Fixes issues with auto-switch redirects removing pre-exisiting URL params. PR#3913 +* Fix: Prevent reducing stock while saving a subscription on the admin edit subscription screen. PR#3926 +* Fix: Use product object to read the original, unmodified length of a cart item during a switch. PR#3929 +* Dev: Trigger create/update webhooks during Subscription REST API calls. PR#3919 +* Dev: Add filters to enable third-parties to change the new and old payment method titles used in subscription changed payment method notes. PR#3908 + +2020-11-25 - version 3.0.11 +* Tweak: Improve the missing customer error message displayed for third-party built checkouts when registration is disabled on checkout. PR#3893 +* Fix: Remove the possibility of a negative calculation of prepaid days on subscription downgrades. PR#3881 +* Fix: Fix issues preventing stores using the $0 Initial Checkout feature from being able to checkout. PR#3887 +* Fix: Remove potential fatal error when processing end-of-prepaid term scheduled actions caused by the subscription not existing. PR#3875 +* Fix: Trigger payment complete actions after renewing early via modal. PR#3888 +* Fix: Performance improvements to limited products running slow queries on the shop page. PR#3895 +* Fix: [PHP 8.0] Only pass array values to call_user_func_array calls. PR#3884 +* Fix: [PHP 8.0] Replaces certain uses of method_exists() with is_callable(). PR#3892 + +2020-11-10 - version 3.0.10 +* Fix: Store shipping line item instance ID separately and copy it to renewal line item meta. PR#3712 +* Fix: Account for the base store tax rates subtracted from line items when paying for renewals manually. PR#3745 +* Fix: Update the persistent cart while paying for renewal orders via the checkout. Fixes division by zero errors while manually renewing. PR#3824 +* Fix: Clear report cache data before regenerating new preset date results preventing infinitely growing report caches. PR#3800 +* Fix: Remove subscription period string transient caching to fix issues after translating. PR#3770 +* Fix: WC 4.7 compatibility. Use filter to change endpoint titles in My Account. PR#3857 +* Fix: When generating product price strings fallback to a default period string if no period is set. PR#3848 +* Fix: Remove uses of jQuery( document ).ready() which was deprecated. PR#3846 +* New: Add option to enable admin to lock in increased parent order line item prices. PR#3816 +* Tweak: Allow admin to set a next payment date in 2 minutes via the edit subscription screen on staging sites. PR#3778 2020-09-29 - version 3.0.9 * Fix: Offset subscription next payment date calculations based on site time. All dates still remain in UTC, but calculations on the 1st and last day of the month will now take into account the site timezone. PR#3708 diff --git a/includes/admin/class-wcs-admin-meta-boxes.php b/includes/admin/class-wcs-admin-meta-boxes.php deleted file mode 100644 index 3f956f5..0000000 --- a/includes/admin/class-wcs-admin-meta-boxes.php +++ /dev/null @@ -1,329 +0,0 @@ -post_type ) { - remove_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Data::save', 40 ); - } - } - - /** - * Print admin styles/scripts - */ - public function enqueue_styles_scripts() { - global $post; - - // Get admin screen id - $screen = get_current_screen(); - $screen_id = isset( $screen->id ) ? $screen->id : ''; - - if ( 'shop_subscription' == $screen_id ) { - - wp_register_script( 'jstz', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/jstz.min.js' ); - - wp_register_script( 'momentjs', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/moment.min.js' ); - - wp_enqueue_script( 'wcs-admin-meta-boxes-subscription', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/meta-boxes-subscription.js', array( 'wc-admin-meta-boxes', 'jstz', 'momentjs' ), WC_VERSION ); - - wp_localize_script( 'wcs-admin-meta-boxes-subscription', 'wcs_admin_meta_boxes', apply_filters( 'woocommerce_subscriptions_admin_meta_boxes_script_parameters', array( - 'i18n_start_date_notice' => __( 'Please enter a start date in the past.', 'woocommerce-subscriptions' ), - 'i18n_past_date_notice' => __( 'Please enter a date at least one hour into the future.', 'woocommerce-subscriptions' ), - 'i18n_next_payment_start_notice' => __( 'Please enter a date after the trial end.', 'woocommerce-subscriptions' ), - 'i18n_next_payment_trial_notice' => __( 'Please enter a date after the start date.', 'woocommerce-subscriptions' ), - 'i18n_trial_end_start_notice' => __( 'Please enter a date after the start date.', 'woocommerce-subscriptions' ), - 'i18n_trial_end_next_notice' => __( 'Please enter a date before the next payment.', 'woocommerce-subscriptions' ), - 'i18n_end_date_notice' => __( 'Please enter a date after the next payment.', 'woocommerce-subscriptions' ), - 'process_renewal_action_warning' => __( "Are you sure you want to process a renewal?\n\nThis will charge the customer and email them the renewal order (if emails are enabled).", 'woocommerce-subscriptions' ), - 'payment_method' => wcs_get_subscription( $post )->get_payment_method(), - 'search_customers_nonce' => wp_create_nonce( 'search-customers' ), - 'get_customer_orders_nonce' => wp_create_nonce( 'get-customer-orders' ), - ) ) ); - } else if ( 'shop_order' == $screen_id ) { - - wp_enqueue_script( 'wcs-admin-meta-boxes-order', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/wcs-meta-boxes-order.js' ); - - wp_localize_script( - 'wcs-admin-meta-boxes-order', - 'wcs_admin_order_meta_boxes', - array( - 'retry_renewal_payment_action_warning' => __( "Are you sure you want to retry payment for this renewal order?\n\nThis will attempt to charge the customer and send renewal order emails (if emails are enabled).", 'woocommerce-subscriptions' ), - ) - ); - } - - // Enqueue the metabox script for coupons. - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.2' ) && in_array( $screen_id, array( 'shop_coupon', 'edit-shop_coupon' ) ) ) { - wp_enqueue_script( - 'wcs-admin-coupon-meta-boxes', - plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/meta-boxes-coupon.js', - array( 'jquery', 'wc-admin-meta-boxes' ), - WC_Subscriptions::$version - ); - } - } - - /** - * Adds actions to the admin edit subscriptions page, if the subscription hasn't ended and the payment method supports them. - * - * @param array $actions An array of available actions - * @return array An array of updated actions - * @since 2.0 - */ - public static function add_subscription_actions( $actions ) { - global $theorder; - - if ( wcs_is_subscription( $theorder ) ) { - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.2' ) ) { - unset( $actions['send_order_details'], $actions['send_order_details_admin'] ); - } - - if ( ! $theorder->has_status( wcs_get_subscription_ended_statuses() ) ) { - if ( $theorder->payment_method_supports( 'subscription_date_changes' ) && $theorder->has_status( 'active' ) ) { - $actions['wcs_process_renewal'] = esc_html__( 'Process renewal', 'woocommerce-subscriptions' ); - } - - if ( count( $theorder->get_related_orders() ) > 0 ) { - $actions['wcs_create_pending_renewal'] = esc_html__( 'Create pending renewal order', 'woocommerce-subscriptions' ); - } else { - $actions['wcs_create_pending_parent'] = esc_html__( 'Create pending parent order', 'woocommerce-subscriptions' ); - } - } - } else if ( self::can_renewal_order_be_retried( $theorder ) ) { - $actions['wcs_retry_renewal_payment'] = esc_html__( 'Retry Renewal Payment', 'woocommerce-subscriptions' ); - } - - return $actions; - } - - /** - * Handles the action request to process a renewal order. - * - * @param array $subscription - * @since 2.0 - */ - public static function process_renewal_action_request( $subscription ) { - $subscription->add_order_note( __( 'Process renewal order action requested by admin.', 'woocommerce-subscriptions' ), false, true ); - do_action( 'woocommerce_scheduled_subscription_payment', $subscription->get_id() ); - } - - /** - * Handles the action request to create a pending renewal order. - * - * @param array $subscription - * @since 2.0 - */ - public static function create_pending_renewal_action_request( $subscription ) { - $subscription->add_order_note( __( 'Create pending renewal order requested by admin action.', 'woocommerce-subscriptions' ), false, true ); - $subscription->update_status( 'on-hold' ); - - $renewal_order = wcs_create_renewal_order( $subscription ); - - if ( ! $subscription->is_manual() ) { - - $renewal_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name - - if ( is_callable( array( $renewal_order, 'save' ) ) ) { // WC 3.0+ - $renewal_order->save(); - } - } - } - - /** - * Handles the action request to create a pending parent order. - * - * @param array $subscription - * @since 2.3 - */ - public static function create_pending_parent_action_request( $subscription ) { - - if ( ! $subscription->has_status( array( 'pending', 'on-hold' ) ) ) { - $subscription->update_status( 'on-hold' ); - } - - $parent_order = wcs_create_order_from_subscription( $subscription, 'parent' ); - - $subscription->set_parent_id( wcs_get_objects_property( $parent_order, 'id' ) ); - $subscription->save(); - - if ( ! $subscription->is_manual() ) { - - $parent_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name - - if ( is_callable( array( $parent_order, 'save' ) ) ) { // WC 3.0+ - $parent_order->save(); - } - } - - wc_maybe_reduce_stock_levels( $parent_order ); - $subscription->add_order_note( __( 'Create pending parent order requested by admin action.', 'woocommerce-subscriptions' ), false, true ); - } - - /** - * Removes order related emails from the available actions. - * - * @param array $available_emails - * @since 2.0 - */ - public static function remove_order_email_actions( $email_actions ) { - global $theorder; - - if ( wcs_is_subscription( $theorder ) ) { - $email_actions = array(); - } - - return $email_actions; - } - - /** - * Process the action request to retry renewal payment for failed renewal orders. - * - * @param WC_Order $order - * @since 2.1 - */ - public static function process_retry_renewal_payment_action_request( $order ) { - - if ( self::can_renewal_order_be_retried( $order ) ) { - // init payment gateways - WC()->payment_gateways(); - - $order->add_order_note( __( 'Retry renewal payment action requested by admin.', 'woocommerce-subscriptions' ), false, true ); - do_action( 'woocommerce_scheduled_subscription_payment_' . wcs_get_objects_property( $order, 'payment_method' ), $order->get_total(), $order ); - } - } - - /** - * Determines if a renewal order payment can be retried. A renewal order payment can only be retried when: - * - Order is a renewal order - * - Order status is failed - * - Order payment method isn't empty - * - Order total > 0 - * - Subscription/s aren't manual - * - Subscription payment method supports date changes - * - Order payment method has_action('woocommerce_scheduled_subscription_payment_..') - * - * @param WC_Order $order - * @return bool - * @since 2.1 - */ - private static function can_renewal_order_be_retried( $order ) { - - $can_be_retried = false; - - if ( wcs_order_contains_renewal( $order ) && $order->needs_payment() && '' != wcs_get_objects_property( $order, 'payment_method' ) ) { - $supports_date_changes = false; - $order_payment_gateway = wc_get_payment_gateway_by_order( $order ); - $order_payment_gateway_supports = ( isset( $order_payment_gateway->id ) ) ? has_action( 'woocommerce_scheduled_subscription_payment_' . $order_payment_gateway->id ) : false; - - foreach ( wcs_get_subscriptions_for_renewal_order( $order ) as $subscription ) { - $supports_date_changes = $subscription->payment_method_supports( 'subscription_date_changes' ); - $is_automatic = ! $subscription->is_manual(); - break; - } - - $can_be_retried = $order_payment_gateway_supports && $supports_date_changes && $is_automatic; - } - - return $can_be_retried; - } - - /** - * Disables stock managment while adding items to a subscription via the edit subscription screen. - * - * @since 3.0.6 - * - * @param string $manage_stock The default manage stock setting. - * @return string Whether the stock should be managed. - */ - public static function override_stock_management( $manage_stock ) { - - // Override stock management while adding line items to a subscription via AJAX. - if ( isset( $_POST['order_id'] ) && wp_verify_nonce( $_REQUEST['security'], 'order-item' ) && doing_action( 'wp_ajax_woocommerce_add_order_item' ) && wcs_is_subscription( absint( wp_unslash( $_POST['order_id'] ) ) ) ) { - $manage_stock = 'no'; - } - - return $manage_stock; - } -} diff --git a/includes/admin/class-wcs-admin-reports.php b/includes/admin/class-wcs-admin-reports.php index 0d8cf13..7abe099 100644 --- a/includes/admin/class-wcs-admin-reports.php +++ b/includes/admin/class-wcs-admin-reports.php @@ -96,17 +96,15 @@ class WCS_Admin_Reports { * @since 1.5 */ public static function reports_scripts() { - global $wp_query, $post; - - $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; - - $screen = get_current_screen(); - $wc_screen_id = sanitize_title( __( 'WooCommerce', 'woocommerce-subscriptions' ) ); + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + $screen = get_current_screen(); + $wc_screen_id = sanitize_title( __( 'WooCommerce', 'woocommerce-subscriptions' ) ); + $version = WC_Subscriptions_Plugin::instance()->get_plugin_version(); // Reports Subscriptions Pages if ( in_array( $screen->id, apply_filters( 'woocommerce_reports_screen_ids', array( $wc_screen_id . '_page_wc-reports', 'toplevel_page_wc-reports', 'dashboard' ) ) ) && isset( $_GET['tab'] ) && 'subscriptions' == $_GET['tab'] ) { - wp_enqueue_script( 'wcs-reports', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/reports.js', array( 'jquery', 'jquery-ui-datepicker', 'wc-reports', 'accounting' ), WC_Subscriptions::$version ); + wp_enqueue_script( 'wcs-reports', WC_Subscriptions_Plugin::instance()->get_plugin_directory_url( 'assets/js/admin/reports.js' ), array( 'jquery', 'jquery-ui-datepicker', 'wc-reports', 'accounting' ), $version ); // Add currency localisation params for axis label wp_localize_script( 'wcs-reports', 'wcs_reports', array( @@ -117,12 +115,12 @@ class WCS_Admin_Reports { 'currency_format' => esc_js( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ), // For accounting JS ) ); - wp_enqueue_script( 'flot-order', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/jquery.flot.orderBars' . $suffix . '.js', array( 'jquery', 'flot' ), WC_Subscriptions::$version ); - wp_enqueue_script( 'flot-axis-labels', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/jquery.flot.axislabels' . $suffix . '.js', array( 'jquery', 'flot' ), WC_Subscriptions::$version ); + wp_enqueue_script( 'flot-order', WC_Subscriptions_Plugin::instance()->get_plugin_directory_url( 'assets/js/admin/jquery.flot.orderBars' ) . $suffix . '.js', array( 'jquery', 'flot' ), $version ); + wp_enqueue_script( 'flot-axis-labels', WC_Subscriptions_Plugin::instance()->get_plugin_directory_url( 'assets/js/admin/jquery.flot.axislabels' ) . $suffix . '.js', array( 'jquery', 'flot' ), $version ); // Add tracks script if tracking is enabled. if ( 'yes' === get_option( 'woocommerce_allow_tracking', 'no' ) ) { - wp_enqueue_script( 'wcs-tracks', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/tracks.js', array( 'jquery' ), WC_Subscriptions::$version, true ); + wp_enqueue_script( 'wcs-tracks', WC_Subscriptions_Plugin::instance()->get_plugin_directory_url( 'assets/js/admin/tracks.js' ), array( 'jquery' ), $version, true ); } } } @@ -174,7 +172,7 @@ class WCS_Admin_Reports { $properties = array( 'orders_count' => array_sum( (array) wp_count_posts( 'shop_order' ) ), 'subscriptions_count' => array_sum( (array) wp_count_posts( 'shop_subscription' ) ), - 'subscriptions_version' => WC_Subscriptions::$version, + 'subscriptions_version' => WC_Subscriptions_Plugin::instance()->get_plugin_version(), ); if ( in_array( $name, array( 'subscription-events-by-date', 'upcoming-recurring-revenue', 'subscription-payment-retry' ), true ) ) { diff --git a/includes/admin/reports/class-wcs-report-cache-manager.php b/includes/admin/reports/class-wcs-report-cache-manager.php index 7a98aaf..79b763f 100644 --- a/includes/admin/reports/class-wcs-report-cache-manager.php +++ b/includes/admin/reports/class-wcs-report-cache-manager.php @@ -80,7 +80,7 @@ class WCS_Report_Cache_Manager { public function __construct() { // Use the old hooks - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $hooks = array( 'woocommerce_order_add_product' => 'woocommerce_new_order_item', @@ -218,12 +218,11 @@ class WCS_Report_Cache_Manager { // Some report classes extend WP_List_Table which has a constructor using methods not available on WP-Cron (and unable to be loaded with a __doing_it_wrong() notice), so they have a static get_data() method and do not need to be instantiated if ( $reflector->isStatic() ) { - + call_user_func( array( $report_class, 'clear_cache' ) ); call_user_func( array( $report_class, 'get_data' ), array( 'no_cache' => true ) ); - } else { - $report = new $report_class(); + $report->clear_cache(); // Classes with a non-static get_data() method can be displayed for different time series, so we need to update the cache for each of those ranges foreach ( array( 'year', 'last_month', 'month', '7day' ) as $range ) { diff --git a/includes/admin/reports/class-wcs-report-dashboard.php b/includes/admin/reports/class-wcs-report-dashboard.php index e2e5e5f..01866aa 100644 --- a/includes/admin/reports/class-wcs-report-dashboard.php +++ b/includes/admin/reports/class-wcs-report-dashboard.php @@ -39,10 +39,10 @@ class WCS_Report_Dashboard { 'no_cache' => false, ); - $args = apply_filters( 'wcs_reports_subscription_dashboard_args', $args ); - $args = wp_parse_args( $args, $default_args ); - - $offset = get_option( 'gmt_offset' ); + $args = apply_filters( 'wcs_reports_subscription_dashboard_args', $args ); + $args = wp_parse_args( $args, $default_args ); + $offset = get_option( 'gmt_offset' ); + $update_cache = false; // Use this once it is merged - wcs_get_gmt_offset_string(); // Convert from Decimal format(eg. 11.5) to a suitable format(eg. +11:30) for CONVERT_TZ() of SQL query. @@ -72,7 +72,7 @@ class WCS_Report_Dashboard { if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) { $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $cached_results[ $query_hash ] = $wpdb->get_var( apply_filters( 'woocommerce_subscription_dashboard_status_widget_signup_query', $query ) ); - set_transient( strtolower( __CLASS__ ), $cached_results, WEEK_IN_SECONDS ); + $update_cache = true; } $report_data->signup_count = $cached_results[ $query_hash ]; @@ -103,7 +103,7 @@ class WCS_Report_Dashboard { if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) { $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $cached_results[ $query_hash ] = $wpdb->get_var( apply_filters( 'woocommerce_subscription_dashboard_status_widget_signup_revenue_query', $query ) ); - set_transient( strtolower( __CLASS__ ), $cached_results, HOUR_IN_SECONDS ); + $update_cache = true; } $report_data->signup_revenue = $cached_results[ $query_hash ]; @@ -131,7 +131,7 @@ class WCS_Report_Dashboard { if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) { $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $cached_results[ $query_hash ] = $wpdb->get_var( apply_filters( 'woocommerce_subscription_dashboard_status_widget_renewal_query', $query ) ); - set_transient( strtolower( __CLASS__ ), $cached_results, HOUR_IN_SECONDS ); + $update_cache = true; } $report_data->renewal_count = $cached_results[ $query_hash ]; @@ -165,7 +165,7 @@ class WCS_Report_Dashboard { if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) { $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $cached_results[ $query_hash ] = $wpdb->get_var( apply_filters( 'woocommerce_subscription_dashboard_status_widget_renewal_revenue_query', $query ) ); - set_transient( strtolower( __CLASS__ ), $cached_results, HOUR_IN_SECONDS ); + $update_cache = true; } $report_data->renewal_revenue = $cached_results[ $query_hash ]; @@ -188,11 +188,15 @@ class WCS_Report_Dashboard { if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) { $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $cached_results[ $query_hash ] = $wpdb->get_var( apply_filters( 'woocommerce_subscription_dashboard_status_widget_cancellation_query', $query ) ); - set_transient( strtolower( __CLASS__ ), $cached_results, HOUR_IN_SECONDS ); + $update_cache = true; } $report_data->cancel_count = $cached_results[ $query_hash ]; + if ( $update_cache ) { + set_transient( strtolower( __CLASS__ ), $cached_results, HOUR_IN_SECONDS ); + } + return $report_data; } @@ -254,6 +258,15 @@ class WCS_Report_Dashboard { * @since 2.1 */ public static function dashboard_scripts() { - wp_enqueue_style( 'wcs-dashboard-report', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/css/dashboard.css', array(), WC_Subscriptions::$version ); + wp_enqueue_style( 'wcs-dashboard-report', WC_Subscriptions_Plugin::instance()->get_plugin_directory_url( 'assets/css/dashboard.css' ), array(), WC_Subscriptions_Plugin::instance()->get_plugin_version() ); + } + + /** + * Clears the cached report data. + * + * @since 3.0.10 + */ + public static function clear_cache() { + delete_transient( strtolower( __CLASS__ ) ); } } diff --git a/includes/admin/reports/class-wcs-report-retention-rate.php b/includes/admin/reports/class-wcs-report-retention-rate.php index d7f1bca..26418cf 100644 --- a/includes/admin/reports/class-wcs-report-retention-rate.php +++ b/includes/admin/reports/class-wcs-report-retention-rate.php @@ -129,7 +129,7 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report { * @return null */ public function output_report() { - include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . '/includes/admin/views/html-report-by-period.php' ); + include( WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'includes/admin/views/html-report-by-period.php' ) ); } /** @@ -172,7 +172,7 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report { var main_chart; jQuery(function(){ - var subscription_lifespans = jQuery.parseJSON( '' ), + var subscription_lifespans = JSON.parse( '' ), unended_subscriptions = report_data->unended_subscriptions ); ?>; var drawGraph = function( highlight ) { @@ -232,7 +232,7 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report { } ); - jQuery('.chart-placeholder').resize(); + jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); diff --git a/includes/admin/reports/class-wcs-report-subscription-by-customer.php b/includes/admin/reports/class-wcs-report-subscription-by-customer.php index 24412f2..20f0d60 100644 --- a/includes/admin/reports/class-wcs-report-subscription-by-customer.php +++ b/includes/admin/reports/class-wcs-report-subscription-by-customer.php @@ -280,4 +280,13 @@ class WCS_Report_Subscription_By_Customer extends WP_List_Table { return $customer_totals; } + + /** + * Clears the cached report data. + * + * @since 3.0.10 + */ + public static function clear_cache() { + delete_transient( strtolower( __CLASS__ ) ); + } } diff --git a/includes/admin/reports/class-wcs-report-subscription-by-product.php b/includes/admin/reports/class-wcs-report-subscription-by-product.php index fe2a3a2..b1d6249 100644 --- a/includes/admin/reports/class-wcs-report-subscription-by-product.php +++ b/includes/admin/reports/class-wcs-report-subscription-by-product.php @@ -304,7 +304,7 @@ class WCS_Report_Subscription_By_Product extends WP_List_Table { } } ); - jQuery('.chart-placeholder.variation_breakdown_chart').resize(); + jQuery('.chart-placeholder.variation_breakdown_chart').trigger( 'resize' ); jQuery.plot( jQuery('.chart-placeholder.product_breakdown_chart'), [ @@ -346,9 +346,18 @@ class WCS_Report_Subscription_By_Product extends WP_List_Table { } } ); - jQuery('.chart-placeholder.product_breakdown_chart').resize(); + jQuery('.chart-placeholder.product_breakdown_chart').trigger( 'resize' ); }); $this->group_by_query, - 'order_status' => '', + 'order_status' => array(), 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, @@ -467,7 +467,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report { set_transient( strtolower( get_class( $this ) ), $cached_results, WEEK_IN_SECONDS ); // Remove this class from the list of classes WC updates on shutdown. Introduced in WC 3.7 - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.7' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.7' ) ) { unset( WC_Admin_Report::$transients_to_update[ strtolower( get_class( $this ) ) ] ); } } @@ -832,7 +832,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report { var main_chart; jQuery(function(){ - var order_data = jQuery.parseJSON( '' ); + var order_data = JSON.parse( '' ); var drawGraph = function( highlight ) { var series = [ { @@ -1107,12 +1107,12 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report { } ); - jQuery('.chart-placeholder').resize(); + jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); - jQuery('.highlight_series').hover( + jQuery('.highlight_series').on( 'hover', function() { drawGraph( jQuery(this).data('series') ); }, @@ -1205,4 +1205,13 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report { return $prepared_data; } + + /** + * Clears the cached report data. + * + * @since 3.0.10 + */ + public function clear_cache() { + delete_transient( strtolower( get_class( $this ) ) ); + } } diff --git a/includes/admin/reports/class-wcs-report-subscription-payment-retry.php b/includes/admin/reports/class-wcs-report-subscription-payment-retry.php index d1a8874..e77504c 100644 --- a/includes/admin/reports/class-wcs-report-subscription-payment-retry.php +++ b/includes/admin/reports/class-wcs-report-subscription-payment-retry.php @@ -239,7 +239,7 @@ class WCS_Report_Subscription_Payment_Retry extends WC_Admin_Report { var main_chart; jQuery(function(){ - var chart_data = jQuery.parseJSON( '' ); + var chart_data = JSON.parse( '' ); var drawGraph = function( highlight ) { var series = [ @@ -378,12 +378,12 @@ class WCS_Report_Subscription_Payment_Retry extends WC_Admin_Report { } ); - jQuery('.chart-placeholder').resize(); + jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); - jQuery('.highlight_series').hover( + jQuery('.highlight_series').on( 'hover', function() { drawGraph( jQuery(this).data('series') ); }, diff --git a/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php b/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php index a4065e8..a2b0a35 100644 --- a/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php +++ b/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php @@ -240,7 +240,7 @@ class WCS_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { var main_chart; jQuery(function(){ - var order_data = jQuery.parseJSON( '' ); + var order_data = JSON.parse( '' ); var drawGraph = function( highlight ) { var series = [ { @@ -331,12 +331,12 @@ class WCS_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { } ); - jQuery('.chart-placeholder').resize(); + jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); - jQuery('.highlight_series').hover( + jQuery('.highlight_series').on( 'hover', function() { drawGraph( jQuery(this).data('series') ); }, @@ -430,4 +430,13 @@ class WCS_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { return $current_range; } + + /** + * Clears the cached query results. + * + * @since 3.0.10 + */ + public function clear_cache() { + delete_transient( strtolower( get_class( $this ) ) ); + } } diff --git a/includes/api/class-wc-rest-subscription-notes-controller.php b/includes/api/class-wc-rest-subscription-notes-controller.php index fb12433..509ee8d 100644 --- a/includes/api/class-wc-rest-subscription-notes-controller.php +++ b/includes/api/class-wc-rest-subscription-notes-controller.php @@ -1,23 +1,16 @@ /notes endpoint. + * Handles requests to the /subscriptions//notes endpoint. * - * @author Prospress - * @since 2.1 + * @package WooCommerce Subscriptions\Rest Api + * @since 3.1.0 */ -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -/** - * REST API Subscription Notes controller class. - * - * @package WooCommerce_Subscriptions/API - * @extends WC_REST_Order_Notes_Controller - */ -class WC_REST_Subscription_Notes_Controller extends WC_REST_Order_Notes_V1_Controller { +defined( 'ABSPATH' ) || exit; + +class WC_REST_Subscription_notes_Controller extends WC_REST_Order_Notes_Controller { /** * Route base. @@ -33,4 +26,18 @@ class WC_REST_Subscription_Notes_Controller extends WC_REST_Order_Notes_V1_Contr */ protected $post_type = 'shop_subscription'; + /** + * Prepare links for the request. + * + * @since 3.1.0 + * + * @param WP_Comment $note + * @return array Links for the given order note. + */ + protected function prepare_links( $note ) { + $links = parent::prepare_links( $note ); + $links['up'] = array( 'href' => rest_url( sprintf( '/%s/subscriptions/%d', $this->namespace, (int) $note->comment_post_ID ) ) ); + + return $links; + } } diff --git a/includes/api/class-wc-rest-subscription-system-status-manager.php b/includes/api/class-wc-rest-subscription-system-status-manager.php new file mode 100644 index 0000000..cdd29b8 --- /dev/null +++ b/includes/api/class-wc-rest-subscription-system-status-manager.php @@ -0,0 +1,148 @@ +/system_status endpoint. + * + * @package WooCommerce Subscriptions\Rest Api + * @since 3.1.0 + */ + +defined( 'ABSPATH' ) || exit; + +class WC_REST_Subscription_System_Status_Manager { + + /** + * Attach callbacks. + */ + public static function init() { + add_filter( 'woocommerce_rest_prepare_system_status', array( __CLASS__, 'add_subscription_fields_to_reponse' ) ); + add_filter( 'woocommerce_rest_system_status_schema', array( __CLASS__, 'add_additional_fields_to_schema' ) ); + } + + /** + * Adds subscription fields to System Status response. + * + * @since 3.1.0 + * + * @param WP_REST_Response $response The base system status response. + * @return WP_REST_Response + */ + public static function add_subscription_fields_to_reponse( $response ) { + $response->data['subscriptions'] = array( + 'wcs_debug' => defined( 'WCS_DEBUG' ) ? WCS_DEBUG : false, + 'mode' => ( WCS_Staging::is_duplicate_site() ) ? __( 'staging', 'woocommerce-subscriptions' ) : __( 'live', 'woocommerce-subscriptions' ), + 'live_url' => esc_url( WCS_Staging::get_site_url_from_source( 'subscriptions_install' ) ), + 'statuses' => array_filter( (array) wp_count_posts( 'shop_subscription' ) ), + 'report_cache_enabled' => ( 'yes' === get_option( 'woocommerce_subscriptions_cache_updates_enabled', 'yes' ) ), + 'cache_update_failures' => absint( get_option( 'woocommerce_subscriptions_cache_updates_failures', 0 ) ), + 'subscriptions_by_payment_gateway' => WCS_Admin_System_Status::get_subscriptions_by_gateway(), + 'payment_gateway_feature_support' => self::get_payment_gateway_feature_support(), + ); + + return $response; + } + + /** + * Gets the store's payment gateways and the features they support. + * + * @since 3.1.0 + * @return array Payment gateway and their features. + */ + private static function get_payment_gateway_feature_support() { + $gateway_features = array(); + + foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway_id => $gateway ) { + // Some gateways include array keys. For consistancy, only send the values. + $gateway_features[ $gateway_id ] = array_values( (array) apply_filters( 'woocommerce_subscriptions_payment_gateway_features_list', $gateway->supports, $gateway ) ); + + if ( 'paypal' === $gateway_id && WCS_PayPal::are_reference_transactions_enabled() ) { + $gateway_features[ $gateway_id ][] = 'paypal_reference_transactions'; + } + } + + return $gateway_features; + } + + /** + * Adds subscription system status fields the system status schema. + * + * @since 3.1.0 + * @param array $schema + * + * @return array the system status schema. + */ + public static function add_additional_fields_to_schema( $schema ) { + + $schema['properties']['subscriptions'] = array( + array( + 'description' => __( 'Subscriptions.', 'woocommerce-subscriptions' ), + 'type' => 'object', + 'context' => array( 'view' ), + 'readonly' => true, + 'properties' => array( + 'wcs_debug_enabled' => array( + 'description' => __( 'WCS debug constant.', 'woocommerce-subscriptions' ), + 'type' => 'boolean', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'mode' => array( + 'description' => __( 'Subscriptions Mode', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'live_url' => array( + 'description' => __( 'Subscriptions Live Site URL', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'format' => 'uri', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'statuses' => array( + 'description' => __( 'Subscriptions broken down by status.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view' ), + 'readonly' => true, + 'items' => array( + 'type' => 'string', + ), + ), + 'report_cache_enabled' => array( + 'description' => __( 'Whether the Report Cache is enabled.', 'woocommerce-subscriptions' ), + 'type' => 'boolean', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'cache_update_failures' => array( + 'description' => __( 'Number of report cache failures.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'subscriptions_by_payment_gateway' => array( + 'description' => __( 'Subscriptions by Payment Gateway.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view' ), + 'readonly' => true, + 'items' => array( + 'type' => 'string', + ), + ), + 'payment_gateway_feature_support' => array( + 'description' => __( 'Payment Gateway Feature Support.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view' ), + 'readonly' => true, + 'items' => array( + 'type' => 'string', + ), + ), + ), + ), + ); + + return $schema; + } +} diff --git a/includes/api/class-wc-rest-subscriptions-controller.php b/includes/api/class-wc-rest-subscriptions-controller.php index 58907a3..01c72f7 100644 --- a/includes/api/class-wc-rest-subscriptions-controller.php +++ b/includes/api/class-wc-rest-subscriptions-controller.php @@ -2,23 +2,15 @@ /** * REST API Subscriptions controller * - * Handles requests to the /subscription endpoint. + * Handles requests to the /subscriptions endpoint. * - * @author Prospress - * @since 2.1 + * @package WooCommerce Subscriptions\Rest Api + * @since 3.1.0 */ -if ( ! defined( 'ABSPATH' ) ) { - exit; -} +defined( 'ABSPATH' ) || exit; -/** - * REST API Subscriptions controller class. - * - * @package WooCommerce_Subscriptions/API - * @extends WC_REST_Orders_Controller - */ -class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { +class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller { /** * Route base. @@ -28,28 +20,38 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { protected $rest_base = 'subscriptions'; /** - * Post type. + * The post type. * * @var string */ protected $post_type = 'shop_subscription'; /** - * Initialize subscription actions and filters - */ - public function __construct() { - add_filter( 'woocommerce_rest_prepare_shop_subscription', array( $this, 'filter_get_subscription_response' ), 10, 3 ); - - add_filter( 'woocommerce_rest_shop_subscription_query', array( $this, 'query_args' ), 10, 2 ); - } - - /** - * Register the routes for subscriptions. + * Register the routes for the subscriptions endpoint. + * + * -- Inherited -- + * GET|POST /subscriptions + * GET|PUT|DELETE /subscriptions/ + * + * -- Subscription specific -- + * GET /subscriptions/status + * GET /subscriptions//orders + * + * @since 3.1.0 */ public function register_routes() { parent::register_routes(); - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/orders', array( + register_rest_route( $this->namespace, "/{$this->rest_base}/statuses", array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_statuses' ), + 'permission_callback' => '__return_true', + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) ); + + register_rest_route( $this->namespace, "/{$this->rest_base}/(?P[\d]+)/orders", array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_subscription_orders' ), @@ -58,259 +60,130 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/statuses', array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_statuses' ), - 'permission_callback' => '__return_true', - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); } /** - * Filter WC_REST_Orders_Controller::get_item response for subscription post types + * Gets the request object. Return false if the ID is not a subscription. * - * @since 2.1 - * @param WP_REST_Response $response - * @param WP_POST $post - * @param WP_REST_Request $request + * @since 3.1.0 + * @param int $id Object ID. + * @return WC_Subscription|bool */ - public function filter_get_subscription_response( $response, $post, $request ) { - $decimal_places = is_null( $request['dp'] ) ? wc_get_price_decimals() : absint( $request['dp'] ); + protected function get_object( $id ) { + $subscription = wcs_get_subscription( $id ); - if ( ! empty( $post->post_type ) && ! empty( $post->ID ) && 'shop_subscription' == $post->post_type ) { - $subscription = wcs_get_subscription( $post->ID ); - - $response->data['billing_period'] = $subscription->get_billing_period(); - $response->data['billing_interval'] = $subscription->get_billing_interval(); - - // Send resubscribe data - $resubscribed_subscriptions = array_filter( $subscription->get_related_orders( 'ids', 'resubscribe' ), 'wcs_is_subscription' ); - $response->data['resubscribed_from'] = strval( wcs_get_objects_property( $subscription, 'subscription_resubscribe' ) ); - $response->data['resubscribed_subscription'] = strval( reset( $resubscribed_subscriptions ) ); // Subscriptions can only be resubscribed to once so return the first and only element. - - foreach ( array( 'start', 'trial_end', 'next_payment', 'end' ) as $date_type ) { - $date = $subscription->get_date( $date_type ); - $response->data[ $date_type . '_date' ] = ( ! empty( $date ) ) ? wc_rest_prepare_date_response( $date ) : ''; - } - - // v1 API includes some date types in site time, include those dates in UTC as well. - $response->data['date_completed_gmt'] = wc_rest_prepare_date_response( $subscription->get_date_completed() ); - $response->data['date_paid_gmt'] = wc_rest_prepare_date_response( $subscription->get_date_paid() ); - $response->data['removed_line_items'] = array(); - - // Include removed line items of a subscription - foreach ( $subscription->get_items( 'line_item_removed' ) as $item_id => $item ) { - $product = $item->get_product(); - $product_id = 0; - $variation_id = 0; - $product_sku = null; - - // Check if the product exists. - if ( is_object( $product ) ) { - $product_id = $item->get_product_id(); - $variation_id = $item->get_variation_id(); - $product_sku = $product->get_sku(); - } - - $item_meta = array(); - - $hideprefix = 'true' === $request['all_item_meta'] ? null : '_'; - - foreach ( $item->get_formatted_meta_data( $hideprefix, true ) as $meta_key => $formatted_meta ) { - $item_meta[] = array( - 'key' => $formatted_meta->key, - 'label' => $formatted_meta->display_key, - 'value' => wc_clean( $formatted_meta->display_value ), - ); - } - - $line_item = array( - 'id' => $item_id, - 'name' => $item['name'], - 'sku' => $product_sku, - 'product_id' => (int) $product_id, - 'variation_id' => (int) $variation_id, - 'quantity' => wc_stock_amount( $item['qty'] ), - 'tax_class' => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '', - 'price' => wc_format_decimal( $subscription->get_item_total( $item, false, false ), $decimal_places ), - 'subtotal' => wc_format_decimal( $subscription->get_line_subtotal( $item, false, false ), $decimal_places ), - 'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $decimal_places ), - 'total' => wc_format_decimal( $subscription->get_line_total( $item, false, false ), $decimal_places ), - 'total_tax' => wc_format_decimal( $item['line_tax'], $decimal_places ), - 'taxes' => array(), - 'meta' => $item_meta, - ); - - $item_line_taxes = maybe_unserialize( $item['line_tax_data'] ); - if ( isset( $item_line_taxes['total'] ) ) { - $line_tax = array(); - - foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) { - $line_tax[ $tax_rate_id ] = array( - 'id' => $tax_rate_id, - 'total' => $tax, - 'subtotal' => '', - ); - } - - foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) { - $line_tax[ $tax_rate_id ]['subtotal'] = $tax; - } - - $line_item['taxes'] = array_values( $line_tax ); - } - - $response->data['removed_line_items'][] = $line_item; - } + if ( ! $subscription || ! is_a( $subscription, 'WC_Subscription' ) ) { + return false; } + return $subscription; + } + + /** + * Prepare a single subscription output for response. + * + * @since 3.1.0 + * + * @param WC_Data $object Subscription object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response + */ + public function prepare_object_for_response( $object, $request ) { + $response = parent::prepare_object_for_response( $object, $request ); + + // When generating the `/subscriptions/[id]/orders` response this function is called to generate related-order data so exit early if this isn't a subscription. + if ( ! wcs_is_subscription( $object ) ) { + return $response; + } + + // Add subscription specific data to the base order response data. + $response->data['billing_period'] = $object->get_billing_period(); + $response->data['billing_interval'] = $object->get_billing_interval(); + + foreach ( wcs_get_subscription_date_types() as $date_type => $date_name ) { + $date = $object->get_date( wcs_normalise_date_type_key( $date_type ) ); + $response->data[ $date_type . '_date_gmt' ] = ( ! empty( $date ) ) ? wc_rest_prepare_date_response( $date ) : ''; + } + + // Some base WC_Order dates need to be pulled from the subscription object to be correct. + $response->data['date_paid'] = wc_rest_prepare_date_response( $object->get_date_paid(), false ); + $response->data['date_paid_gmt'] = wc_rest_prepare_date_response( $object->get_date_paid() ); + $response->data['date_completed'] = wc_rest_prepare_date_response( $object->get_date_completed(), false ); + $response->data['date_completed_gmt'] = wc_rest_prepare_date_response( $object->get_date_completed() ); + + // Include resubscribe data. + $resubscribed_subscriptions = array_filter( $object->get_related_orders( 'ids', 'resubscribe' ), 'wcs_is_subscription' ); + $response->data['resubscribed_from'] = strval( $object->get_meta( '_subscription_resubscribe' ) ); + $response->data['resubscribed_subscription'] = strval( reset( $resubscribed_subscriptions ) ); // Subscriptions can only be resubscribed to once so return the first and only element. + + // Include the removed line items. + $response->data['removed_line_items'] = array(); + + foreach ( $object->get_items( 'line_item_removed' ) as $item ) { + $response->data['removed_line_items'][] = $this->get_order_item_data( $item ); + } + + // Remove non-subscription properties + unset( $response->data['cart_hash'] ); + unset( $response->data['transaction_id'] ); + return $response; } /** - * Sets the order_total value on the subscription after WC_REST_Orders_Controller::create_order - * calls calculate_totals(). This allows store admins to create a recurring payment via the api - * without needing to attach a product to the subscription. + * Gets the /subscriptions/statuses response. * - * @since 2.1 - * @param WP_REST_Request $request + * @since 3.1.0 + * @return WP_REST_Response The response object. */ - protected function create_order( $request ) { - try { - if ( ! is_null( $request['customer_id'] ) && 0 !== $request['customer_id'] && false === get_user_by( 'id', $request['customer_id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce-subscriptions' ), 400 ); - } - - // If the start date is not set in the request, set its default to now - if ( ! isset( $request['start_date'] ) ) { - $request['start_date'] = gmdate( 'Y-m-d H:i:s' ); - } - - // prepare all subscription data from the request - $subscription = $this->prepare_item_for_database( $request ); - $subscription->set_created_via( 'rest-api' ); - $subscription->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); - $subscription->calculate_totals(); - - // allow the order total to be overriden (i.e. if you want to have a subscription with no order items but a flat $10.00 recurring payment ) - if ( isset( $request['order_total'] ) ) { - $subscription->set_total( wc_format_decimal( $request['order_total'], get_option( 'woocommerce_price_num_decimals' ) ) ); - } - - // Store the post meta on the subscription after it's saved, this is to avoid compat. issue with the filters in WC_Subscriptions::set_payment_method_meta() expecting the $subscription to have an ID (therefore it needs to be called after the WC_Subscription has been saved) - $payment_data = ( ! empty( $request['payment_details'] ) ) ? $request['payment_details'] : array(); - if ( empty( $payment_data['payment_details']['method_id'] ) && ! empty( $request['payment_method'] ) ) { - $payment_data['method_id'] = $request['payment_method']; - } - - $this->update_payment_method( $subscription, $payment_data ); - - $subscription->save(); - - // Handle set paid. - if ( true === $request['set_paid'] ) { - $subscription->payment_complete( $request['transaction_id'] ); - } - - return $subscription->get_id(); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } + public function get_statuses() { + return rest_ensure_response( wcs_get_subscription_statuses() ); } /** - * Overrides WC_REST_Orders_Controller::update_order to update subscription specific meta - * calls parent::update_order to update the rest. + * Gets the /subscriptions/[id]/orders response. * - * @since 2.1 - * @param WP_REST_Request $request - * @param WP_POST $post - */ - protected function update_order( $request ) { - try { - $subscription = $this->prepare_item_for_database( $request ); - - // If any line items have changed, recalculate subscription totals. - if ( isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) { - $subscription->calculate_totals(); - } - - // allow the order total to be overriden (i.e. if you want to have a subscription with no order items but a flat $10.00 recurring payment ) - if ( isset( $request['order_total'] ) ) { - $subscription->set_total( wc_format_decimal( $request['order_total'], get_option( 'woocommerce_price_num_decimals' ) ) ); - } - - $subscription->save(); - - // Update the post meta on the subscription after it's saved, this is to avoid compat. issue with the filters in WC_Subscriptions::set_payment_method_meta() expecting the $subscription to have an ID (therefore it needs to be called after the WC_Subscription has been saved) - $payment_data = ( ! empty( $request['payment_details'] ) ) ? $request['payment_details'] : array(); - $existing_payment_method_id = $subscription->get_payment_method(); - - if ( empty( $payment_data['method_id'] ) && isset( $request['payment_method'] ) ) { - $payment_data['method_id'] = $request['payment_method']; - - } elseif ( ! empty( $existing_payment_method_id ) ) { - $payment_data['method_id'] = $existing_payment_method_id; - } - - if ( isset( $payment_data['method_id'] ) ) { - $this->update_payment_method( $subscription, $payment_data, true ); - } - - // Handle set paid. - if ( $subscription->needs_payment() && true === $request['set_paid'] ) { - $subscription->payment_complete(); - } - - return $subscription->get_id(); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Get subscription orders + * @since 3.1.0 * - * @since 2.1 - * @param WP_REST_Request $request - * @return WP_Error|WP_REST_Response $response + * @param WP_REST_Request $request The request object. + * @return WP_Error|WP_REST_Response $response The response or an error if one occurs. */ public function get_subscription_orders( $request ) { - $id = (int) $request['id']; + $id = absint( $request['id'] ); if ( empty( $id ) || ! wcs_is_subscription( $id ) ) { - return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', __( 'Invalid subscription id.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); + return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', __( 'Invalid subscription ID.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); } - $this->post_type = 'shop_order'; - $subscription = wcs_get_subscription( $id ); - $subscription_orders = $subscription->get_related_orders(); + $subscription = wcs_get_subscription( $id ); + + if ( ! $subscription ) { + return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', sprintf( __( 'Failed to load subscription object with the ID %d.', 'woocommerce-subscriptions' ), $id ), array( 'status' => 404 ) ); + } $orders = array(); - foreach ( $subscription_orders as $order_id ) { - $post = get_post( $order_id ); - if ( ! wc_rest_check_post_permissions( $this->post_type, 'read', $post->ID ) ) { - continue; - } + foreach ( array( 'parent', 'renewal', 'switch' ) as $order_type ) { + foreach ( $subscription->get_related_orders( 'ids', $order_type ) as $order_id ) { - $response = $this->prepare_item_for_response( $post, $request ); - - foreach ( array( 'parent', 'renewal', 'switch' ) as $order_type ) { - if ( wcs_order_contains_subscription( $order_id, $order_type ) ) { - $response->data['order_type'] = $order_type . '_order'; - break; + if ( ! wc_rest_check_post_permissions( 'shop_order', 'read', $order_id ) ) { + continue; } - } - $orders[] = $this->prepare_response_for_collection( $response ); + // Validate that the order can be loaded before trying to generate a response object for it. + $order = wc_get_order( $order_id ); + + if ( ! $order ) { + continue; + } + + $response = $this->prepare_object_for_response( $order, $request ); + + // Add the order's relationship to the response. + $response->data['order_type'] = $order_type . '_order'; + + $orders[] = $this->prepare_response_for_collection( $response ); + } } $response = rest_ensure_response( $orders ); @@ -320,77 +193,318 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { return apply_filters( 'wcs_rest_subscription_orders_response', $response, $request ); } - /** - * Get subscription statuses - * - * @since 2.1 - */ - public function get_statuses() { - return rest_ensure_response( wcs_get_subscription_statuses() ); - } - /** * Overrides WC_REST_Orders_Controller::get_order_statuses() so that subscription statuses are - * validated correctly in WC_REST_Orders_Controller::get_collection_params() + * validated correctly. * - * @since 2.1 + * @since 3.1.0 + * @return array An array of valid subscription statuses. */ protected function get_order_statuses() { $subscription_statuses = array(); - foreach ( array_keys( wcs_get_subscription_statuses() ) as $status ) { + foreach ( wcs_get_subscription_statuses() as $status => $status_name ) { $subscription_statuses[] = str_replace( 'wc-', '', $status ); } + return $subscription_statuses; } /** - * Validate and update payment method on a subscription + * Prepares a single subscription for creation or update. * - * @since 2.1 - * @param WC_Subscription $subscription - * @param array $data - * @param bool $updating + * @since 3.1.0 + * + * @param WP_REST_Request $request Request object. + * @param bool $creating If the request is for creating a new object. + * @return WP_Error|WC_Subscription */ - public function update_payment_method( $subscription, $data, $updating = false ) { - $payment_method = ( ! empty( $data['method_id'] ) ) ? $data['method_id'] : ''; + public function prepare_object_for_database( $request, $creating = false ) { + $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; + $subscription = new WC_Subscription( $id ); + $schema = $this->get_item_schema(); + $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - try { - if ( $updating && ! array_key_exists( $payment_method, WCS_Change_Payment_Method_Admin::get_valid_payment_methods( $subscription ) ) ) { - throw new Exception( __( 'Gateway does not support admin changing the payment method on a Subscription.', 'woocommerce-subscriptions' ) ); + // Prepare variables for properties which need to be saved late (like status) or in a group (dates and payment data). + $status = ''; + $payment_method = ''; + $payment_meta = array(); + $dates = array(); + + // If the start date is not set in the request, set its default to now. + if ( ! isset( $request['start_date'] ) ) { + $request['start_date'] = gmdate( 'Y-m-d H:i:s' ); + } + + // Both setting (set_status()) and updating (update_status()) are valid ways for requests to set a subscription's status. + $status_transition = 'set'; + + foreach ( $data_keys as $i => $key ) { + $value = $request[ $key ]; + + if ( is_null( $value ) ) { + continue; } - $payment_method_meta = apply_filters( 'woocommerce_subscription_payment_meta', array(), $subscription ); - - // Reload the subscription to update the meta values. - // In particular, the update_post_meta() called while _stripe_card_id is updated to _stripe_source_id - $subscription = wcs_get_subscription( $subscription->get_id() ); - - if ( isset( $payment_method_meta[ $payment_method ] ) ) { - $payment_method_meta = $payment_method_meta[ $payment_method ]; - - if ( ! empty( $payment_method_meta ) ) { - - foreach ( $payment_method_meta as $meta_table => &$meta ) { - if ( ! is_array( $meta ) ) { - continue; - } - - foreach ( $meta as $meta_key => &$meta_data ) { - - if ( isset( $data[ $meta_table ][ $meta_key ] ) ) { - $meta_data['value'] = $data[ $meta_table ][ $meta_key ]; + switch ( $key ) { + case 'parent_id': + $subscription->set_parent_id( $value ); + break; + case 'transition_status': + $status_transition = 'update'; + case 'status': + // This needs to be done later so status changes take into account other data like dates. + $status = $value; + break; + case 'billing': + case 'shipping': + $this->update_address( $subscription, $value, $key ); + break; + case 'start_date': + case 'trial_end': + case 'next_payment_date': + case 'cancelled_date': + case 'end_date': + // Group all the subscription date properties so they can be validated together. + $dates[ $key ] = $value; + break; + case 'payment_method': + $payment_method = $value; + break; + case 'payment_details': + // Format the value in a way payment gateways expect so it can be validated. + $payment_meta = $value; + break; + case 'line_items': + case 'shipping_lines': + case 'fee_lines': + if ( is_array( $value ) ) { + foreach ( $value as $item ) { + if ( is_array( $item ) ) { + if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { + if ( isset( $item['id'] ) ) { + $subscription->remove_item( $item['id'] ); + } + } else { + $this->set_item( $subscription, $key, $item ); + } } } } + break; + case 'meta_data': + if ( is_array( $value ) ) { + foreach ( $value as $meta ) { + $subscription->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); + } + } + break; + default: + if ( is_callable( array( $subscription, "set_{$key}" ) ) ) { + $subscription->{"set_{$key}"}( $value ); + } + break; + } + } + + if ( ! empty( $payment_method ) ) { + $this->update_payment_method( $subscription, $payment_method, $payment_meta ); + } + + if ( ! empty( $dates ) ) { + // If the start date is not set in the request when a subscription is created with an active status, set its default to now. + if ( 'active' === $status && empty( $id ) && ! isset( $dates['start_date'] ) ) { + $dates['start_date'] = gmdate( 'Y-m-d H:i:s' ); + } + + try { + $subscription->update_dates( $dates ); + } catch ( Exception $e ) { + throw new WC_REST_Exception( 'woocommerce_rest_invalid_payment_data', sprintf( __( 'Subscription dates could not be set. Error message: %s', 'woocommerce-subscriptions' ), $e->getMessage() ), 400 ); + } + } + + if ( ! empty( $status ) ) { + if ( 'set' === $status_transition ) { + $subscription->set_status( $status ); + } else { + $subscription->update_status( $status ); + $request['status'] = $status; // Set the request status so parent::save_object() doesn't set it to the default 'pending' status. + } + } + + /** + * Filters an object before it is inserted via the REST API. + * + * The dynamic portion of the hook name, `$this->post_type`, + * refers to the object type slug. + * + * @param WC_Subscription $subscription The subscription object. + * @param WP_REST_Request $request Request object. + * @param bool $creating If is creating a new object. + */ + return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $subscription, $request, $creating ); + } + + /** + * Adds additional item schema information for subscription requests. + * + * @since 3.1.0 + * @return array + */ + public function get_item_schema() { + $schema = parent::get_item_schema(); + + // Base order schema overrides. + $schema['properties']['status']['description'] = __( 'Subscription status.', 'woocommerce-subscriptions' ); + $schema['properties']['status']['enum'] = $this->get_order_statuses(); + + $schema['properties']['created_via']['description'] = __( 'Where the subscription was created.', 'woocommerce-subscriptions' ); + $schema['properties']['currency']['description'] = __( 'Currency the subscription was created with, in ISO format.', 'woocommerce-subscriptions' ); + $schema['properties']['date_created']['description'] = __( "The date the subscription was created, in the site's timezone.", 'woocommerce-subscriptions' ); + $schema['properties']['date_created_gmt']['description'] = __( 'The date the subscription was created, as GMT.', 'woocommerce-subscriptions' ); + $schema['properties']['date_modified']['description'] = __( "The date the subscription was last modified, in the site's timezone.", 'woocommerce-subscriptions' ); + $schema['properties']['date_modified_gmt']['description'] = __( 'The date the subscription was last modified, as GMT.', 'woocommerce-subscriptions' ); + $schema['properties']['customer_id']['description'] = __( 'User ID who owns the subscription.', 'woocommerce-subscriptions' ); + + unset( $schema['properties']['transaction_id'] ); + unset( $schema['properties']['refunds'] ); + unset( $schema['properties']['set_paid'] ); + unset( $schema['properties']['cart_hash'] ); + + // Add subscription schema. + $schema['properties'] += array( + 'transition_status' => array( + 'description' => __( 'The status to transition a subscription to.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'edit' ), + 'enum' => $this->get_order_statuses(), + ), + 'billing_interval' => array( + 'description' => __( 'The number of billing periods between subscription renewals.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'billing_period' => array( + 'description' => __( 'Billing period for the subscription.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'enum' => array_keys( wcs_get_subscription_period_strings() ), + 'context' => array( 'view', 'edit' ), + ), + 'payment_details' => array( + 'description' => __( 'Subscription payment details.', 'woocommerce-subscriptions' ), + 'type' => 'object', + 'context' => array( 'edit' ), + 'properties' => array( + 'post_meta' => array( + 'description' => __( 'Payment method meta and token in a post_meta_key: token format.', 'woocommerce-subscriptions' ), + 'type' => 'object', + 'context' => array( 'edit' ), + ), + 'user_meta' => array( + 'description' => __( 'Payment method meta and token in a user_meta_key : token format.', 'woocommerce-subscriptions' ), + 'type' => 'object', + 'context' => array( 'view' ), + ), + ), + ), + 'start_date' => array( + 'description' => __( "The subscription's start date, as GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'trial_date' => array( + 'description' => __( "The subscription's trial date, as GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'next_payment_date' => array( + 'description' => __( "The subscription's next payment date, as GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'cancelled_date' => array( + 'description' => __( "The subscription's cancelled date, as GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'end_date' => array( + 'description' => __( "The subscription's end date, as GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + ); + + return $schema; + } + + /** + * Get the query params for collections. + * + * @since 3.1.0 + * @return array + */ + public function get_collection_params() { + $params = parent::get_collection_params(); + + // Override the base order status description to be subscription specific. + $params['status']['description'] = __( 'Limit result set to subscriptions which have specific statuses.', 'woocommerce-subscriptions' ); + return $params; + } + + /** + * Gets an object's links to include in the response. + * + * Because this class also handles retreiving order data, we need + * to edit the links generated so the correct REST API href is included + * when its generated for an order. + * + * @since 3.1.0 + * + * @param WC_Data $object Object data. + * @param WP_REST_Request $request Request object. + * @return array Links for the given object. + */ + protected function prepare_links( $object, $request ) { + $links = parent::prepare_links( $object, $request ); + + if ( isset( $links['self'] ) && wcs_is_order( $object ) ) { + $links['self'] = array( + 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, 'orders', $object->get_id() ) ), + ); + } + + return $links; + } + + /** + * Updates a subscription's payment method and meta from data provided in a REST API request. + * + * @since 3.1.0 + * + * @param WC_Subscription $subscription The subscription to update. + * @param string $payment_method The ID of the payment method to set. + * @param array $payment_meta The payment method meta. + */ + public function update_payment_method( $subscription, $payment_method, $payment_meta ) { + $updating_subscription = (bool) $subscription->get_id(); + + try { + if ( $updating_subscription && ! array_key_exists( $payment_method, WCS_Change_Payment_Method_Admin::get_valid_payment_methods( $subscription ) ) ) { + // translators: placeholder is the payment method ID. + throw new Exception( sprintf( __( 'The %s payment gateway does not support admin changing the payment method.', 'woocommerce-subscriptions' ), $payment_method ) ); + } + + // Format the payment meta in the way payment gateways expect so it can be validated. + $payment_method_meta = array(); + + foreach ( $payment_meta as $table => $meta ) { + foreach ( $meta as $meta_key => $value ) { + $payment_method_meta[ $table ][ $meta_key ] = array( 'value' => $value ); } } $subscription->set_payment_method( $payment_method, $payment_method_meta ); - - // Save the subscription to reflect the new values - $subscription->save(); - } catch ( Exception $e ) { $subscription->set_payment_method(); $subscription->save(); @@ -398,380 +512,4 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { throw new WC_REST_Exception( 'woocommerce_rest_invalid_payment_data', sprintf( __( 'Subscription payment method could not be set to %1$s with error message: %2$s', 'woocommerce-subscriptions' ), $payment_method, $e->getMessage() ), 400 ); } } - - /** - * Prepare a single subscription for create. - * - * @param WP_REST_Request $request Request object. - * @return WP_Error|WC_Subscription $data Object. - */ - protected function prepare_item_for_database( $request ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $subscription = new WC_Subscription( $id ); - $schema = $this->get_item_schema(); - $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - - $dates_to_update = array(); - - // Handle all writable props - foreach ( $data_keys as $key ) { - $value = $request[ $key ]; - - if ( ! is_null( $value ) ) { - switch ( $key ) { - case 'billing': - case 'shipping': - $this->update_address( $subscription, $value, $key ); - break; - case 'line_items': - case 'shipping_lines': - case 'fee_lines': - case 'coupon_lines': - if ( is_array( $value ) ) { - foreach ( $value as $item ) { - if ( is_array( $item ) ) { - if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { - $subscription->remove_item( $item['id'] ); - } else { - $this->set_item( $subscription, $key, $item ); - } - } - } - } - break; - case 'transition_status': - $subscription->update_status( $value ); - break; - case 'start_date': - case 'trial_end_date': - case 'next_payment_date': - case 'end_date': - $dates_to_update[ $key ] = $value; - break; - default: - if ( is_callable( array( $subscription, "set_{$key}" ) ) ) { - $subscription->{"set_{$key}"}( $value ); - } - break; - } - } - } - - $subscription->save(); - - try { - if ( ! empty( $dates_to_update ) ) { - $subscription->update_dates( $dates_to_update ); - } - } catch ( Exception $e ) { - // translators: placeholder is an error message. - throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_subscription_dates', sprintf( __( 'Updating subscription dates errored with message: %s', 'woocommerce-subscriptions' ), $e->getMessage() ), 400 ); - } - - /** - * Filter the data for the insert. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for the response. - * - * @param WC_Subscription $subscription The subscription object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $subscription, $request ); - } - - /** - * Adds additional item schema information for subscription requests - * - * @since 2.1 - */ - public function get_item_schema() { - $schema = parent::get_item_schema(); - - $subscriptions_schema = array( - 'transition_status' => array( - 'description' => __( 'The status to transition the subscription to. Unlike the "status" param, this will calculate and update the subscription dates.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'enum' => $this->get_order_statuses(), - 'context' => array( 'edit' ), - ), - 'billing_interval' => array( - 'description' => __( 'The number of billing periods between subscription renewals.', 'woocommerce-subscriptions' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'billing_period' => array( - 'description' => __( 'Billing period for the subscription.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'enum' => array_keys( wcs_get_subscription_period_strings() ), - 'context' => array( 'view', 'edit' ), - ), - 'payment_details' => array( - 'description' => __( 'Subscription payment details.', 'woocommerce-subscriptions' ), - 'type' => 'object', - 'context' => array( 'edit' ), - 'properties' => array( - 'method_id' => array( - 'description' => __( 'Payment gateway ID.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - ), - ), - 'start_date' => array( - 'description' => __( "The subscription's start date.", 'woocommerce-subscriptions' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'trial_end_date' => array( - 'description' => __( "The subscription's trial date", 'woocommerce-subscriptions' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'next_payment_date' => array( - 'description' => __( "The subscription's next payment date.", 'woocommerce-subscriptions' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'end_date' => array( - 'description' => __( "The subscription's end date.", 'woocommerce-subscriptions' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'resubscribed_from' => array( - 'description' => __( "The subscription's original subscription ID if this is a resubscribed subscription.", 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'resubscribed_subscription' => array( - 'description' => __( "The subscription's resubscribed subscription ID.", 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'date_completed_gmt' => array( - 'description' => __( "The date the subscription's latest order was completed, in GMT.", 'woocommerce-subscriptions' ), - 'type' => 'date-time', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'date_paid_gmt' => array( - 'description' => __( "The date the subscription's latest order was paid, in GMT.", 'woocommerce-subscriptions' ), - 'type' => 'date-time', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'removed_line_items' => array( - 'description' => __( 'Removed line items data.', 'woocommerce-subscriptions' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-subscriptions' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-subscriptions' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sku' => array( - 'description' => __( 'Product SKU.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Product ID.', 'woocommerce-subscriptions' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'variation_id' => array( - 'description' => __( 'Variation ID, if applicable.', 'woocommerce-subscriptions' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'quantity' => array( - 'description' => __( 'Quantity ordered.', 'woocommerce-subscriptions' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class of product.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'price' => array( - 'description' => __( 'Product price.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Line subtotal (before discounts).', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'subtotal_tax' => array( - 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-subscriptions' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-subscriptions' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'meta' => array( - 'description' => __( 'Removed line item meta data.', 'woocommerce-subscriptions' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'Meta label.', 'woocommerce-subscriptions' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-subscriptions' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ), - ), - ); - - $schema['properties'] += $subscriptions_schema; - return $schema; - } - - /** - * Deprecated functions - */ - - /** - * Prepare subscription data for create. - * - * Now that we override WC_REST_Orders_V1_Controller::prepare_item_for_database() function, - * we no longer need to prepare these args - * - * @since 2.1 - * @param stdClass $data - * @param WP_REST_Request $request Request object. - * @return stdClass - * @deprecated 2.2 - */ - public function prepare_subscription_args( $data, $request ) { - wcs_deprecated_function( __METHOD__, '2.2' ); - - $data->billing_interval = $request['billing_interval']; - $data->billing_period = $request['billing_period']; - - foreach ( array( 'start', 'trial_end', 'end', 'next_payment' ) as $date_type ) { - if ( ! empty( $request[ $date_type . '_date' ] ) ) { - $date_type_key = ( 'start' === $date_type ) ? 'date_created' : $date_type . '_date'; - $data->{$date_type_key} = $request[ $date_type . '_date' ]; - } - } - - $data->payment_details = ! empty( $request['payment_details'] ) ? $request['payment_details'] : ''; - $data->payment_method = ! empty( $request['payment_method'] ) ? $request['payment_method'] : ''; - - return $data; - } - - /** - * Update or set the subscription schedule with the request data. - * - * - * @since 2.1 - * @param WC_Subscription $subscription - * @param array $data - * @deprecated 2.2 - */ - public function update_schedule( $subscription, $data ) { - wcs_deprecated_function( __METHOD__, '2.2', 'WC_REST_Subscriptions_Controller::prepare_item_for_database() now prepares the billing interval/period and dates' ); - - if ( isset( $data['billing_interval'] ) ) { - $subscription->set_billing_interval( absint( $data['billing_interval'] ) ); - } - - if ( ! empty( $data['billing_period'] ) ) { - $subscription->set_billing_period( $data['billing_period'] ); - } - - try { - $dates_to_update = array(); - - foreach ( array( 'start', 'trial_end', 'end', 'next_payment' ) as $date_type ) { - if ( isset( $data[ $date_type . '_date' ] ) ) { - $date_type_key = ( 'start' === $date_type ) ? 'date_created' : $date_type; - $dates_to_update[ $date_type_key ] = $data[ $date_type . '_date' ]; - } - } - - if ( ! empty( $dates_to_update ) ) { - $subscription->update_dates( $dates_to_update ); - } - } catch ( Exception $e ) { - // translators: placeholder is an error message. - throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_subscription_dates', sprintf( __( 'Updating subscription dates errored with message: %s', 'woocommerce-subscriptions' ), $e->getMessage() ), 400 ); - } - } } diff --git a/includes/api/legacy/class-wc-api-subscriptions.php b/includes/api/legacy/class-wc-api-subscriptions.php index 02dc8df..b875b66 100644 --- a/includes/api/legacy/class-wc-api-subscriptions.php +++ b/includes/api/legacy/class-wc-api-subscriptions.php @@ -302,14 +302,13 @@ class WC_API_Subscriptions extends WC_API_Orders { * @since 2.0 */ public function update_payment_method( $subscription, $payment_details, $updating ) { - global $wpdb; - $payment_gateways = WC()->payment_gateways->get_available_payment_gateways(); $payment_method = ( ! empty( $payment_details['method_id'] ) ) ? $payment_details['method_id'] : 'manual'; $payment_gateway = ( isset( $payment_gateways[ $payment_details['method_id'] ] ) ) ? $payment_gateways[ $payment_details['method_id'] ] : ''; try { - $wpdb->query( 'START TRANSACTION' ); + $transaction = new WCS_SQL_Transaction(); + $transaction->start(); if ( $updating && ! array_key_exists( $payment_method, WCS_Change_Payment_Method_Admin::get_valid_payment_methods( $subscription ) ) ) { throw new Exception( 'wcs_api_edit_subscription_error', __( 'Gateway does not support admin changing the payment method on a Subscription.', 'woocommerce-subscriptions' ) ); @@ -344,10 +343,10 @@ class WC_API_Subscriptions extends WC_API_Orders { $subscription->set_payment_method( $payment_gateway, $payment_method_meta ); - $wpdb->query( 'COMMIT' ); + $transaction->commit(); } catch ( Exception $e ) { - $wpdb->query( 'ROLLBACK' ); + $transaction->rollback(); // translators: 1$: gateway id, 2$: error message throw new Exception( sprintf( __( 'Subscription payment method could not be set to %1$s and has been set to manual with error message: %2$s', 'woocommerce-subscriptions' ), ( ! empty( $payment_gateway->id ) ) ? $payment_gateway->id : 'manual', $e->getMessage() ) ); diff --git a/includes/api/legacy/class-wc-rest-subscriptions-controller.php b/includes/api/legacy/class-wc-rest-subscriptions-controller.php index af0aac4..82fe7d5 100644 --- a/includes/api/legacy/class-wc-rest-subscriptions-controller.php +++ b/includes/api/legacy/class-wc-rest-subscriptions-controller.php @@ -166,7 +166,7 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller { * @return WP_Error|WP_REST_Response $response */ public function get_subscription_orders( $request ) { - $id = (int) $request['id']; + $id = absint( $request['id'] ); if ( empty( $id ) || ! wcs_is_subscription( $id ) ) { return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', __( 'Invalid subscription id.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); diff --git a/includes/api/v1/class-wc-rest-subscription-notes-v1-controller.php b/includes/api/v1/class-wc-rest-subscription-notes-v1-controller.php new file mode 100644 index 0000000..e85746f --- /dev/null +++ b/includes/api/v1/class-wc-rest-subscription-notes-v1-controller.php @@ -0,0 +1,36 @@ +/notes endpoint. + * + * @author Prospress + * @since 2.1 + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * REST API Subscription Notes controller class. + * + * @package WooCommerce_Subscriptions/API + * @extends WC_REST_Order_Notes_Controller + */ +class WC_REST_Subscription_Notes_V1_Controller extends WC_REST_Order_Notes_V1_Controller { + + /** + * Route base. + * + * @var string + */ + protected $rest_base = 'subscriptions/(?P[\d]+)/notes'; + + /** + * Post type. + * + * @var string + */ + protected $post_type = 'shop_subscription'; + +} diff --git a/includes/api/v1/class-wc-rest-subscriptions-v1-controller.php b/includes/api/v1/class-wc-rest-subscriptions-v1-controller.php new file mode 100644 index 0000000..ea99587 --- /dev/null +++ b/includes/api/v1/class-wc-rest-subscriptions-v1-controller.php @@ -0,0 +1,786 @@ +namespace, '/' . $this->rest_base . '/(?P[\d]+)/orders', array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_subscription_orders' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => $this->get_collection_params(), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) ); + + register_rest_route( $this->namespace, '/' . $this->rest_base . '/statuses', array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_statuses' ), + 'permission_callback' => '__return_true', + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) ); + } + + /** + * Filter WC_REST_Orders_Controller::get_item response for subscription post types + * + * @since 2.1 + * @param WP_REST_Response $response + * @param WP_POST $post + * @param WP_REST_Request $request + */ + public function filter_get_subscription_response( $response, $post, $request ) { + $decimal_places = is_null( $request['dp'] ) ? wc_get_price_decimals() : absint( $request['dp'] ); + + if ( ! empty( $post->post_type ) && ! empty( $post->ID ) && 'shop_subscription' == $post->post_type ) { + $subscription = wcs_get_subscription( $post->ID ); + + $response->data['billing_period'] = $subscription->get_billing_period(); + $response->data['billing_interval'] = $subscription->get_billing_interval(); + + // Send resubscribe data + $resubscribed_subscriptions = array_filter( $subscription->get_related_orders( 'ids', 'resubscribe' ), 'wcs_is_subscription' ); + $response->data['resubscribed_from'] = strval( wcs_get_objects_property( $subscription, 'subscription_resubscribe' ) ); + $response->data['resubscribed_subscription'] = strval( reset( $resubscribed_subscriptions ) ); // Subscriptions can only be resubscribed to once so return the first and only element. + + foreach ( array( 'start', 'trial_end', 'next_payment', 'end' ) as $date_type ) { + $date = $subscription->get_date( $date_type ); + $response->data[ $date_type . '_date' ] = ( ! empty( $date ) ) ? wc_rest_prepare_date_response( $date ) : ''; + } + + // v1 API includes some date types in site time, include those dates in UTC as well. + $response->data['date_completed_gmt'] = wc_rest_prepare_date_response( $subscription->get_date_completed() ); + $response->data['date_paid_gmt'] = wc_rest_prepare_date_response( $subscription->get_date_paid() ); + $response->data['removed_line_items'] = array(); + + // Include removed line items of a subscription + foreach ( $subscription->get_items( 'line_item_removed' ) as $item_id => $item ) { + $product = $item->get_product(); + $product_id = 0; + $variation_id = 0; + $product_sku = null; + + // Check if the product exists. + if ( is_object( $product ) ) { + $product_id = $item->get_product_id(); + $variation_id = $item->get_variation_id(); + $product_sku = $product->get_sku(); + } + + $item_meta = array(); + + $hideprefix = 'true' === $request['all_item_meta'] ? null : '_'; + + foreach ( $item->get_formatted_meta_data( $hideprefix, true ) as $meta_key => $formatted_meta ) { + $item_meta[] = array( + 'key' => $formatted_meta->key, + 'label' => $formatted_meta->display_key, + 'value' => wc_clean( $formatted_meta->display_value ), + ); + } + + $line_item = array( + 'id' => $item_id, + 'name' => $item['name'], + 'sku' => $product_sku, + 'product_id' => (int) $product_id, + 'variation_id' => (int) $variation_id, + 'quantity' => wc_stock_amount( $item['qty'] ), + 'tax_class' => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '', + 'price' => wc_format_decimal( $subscription->get_item_total( $item, false, false ), $decimal_places ), + 'subtotal' => wc_format_decimal( $subscription->get_line_subtotal( $item, false, false ), $decimal_places ), + 'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $decimal_places ), + 'total' => wc_format_decimal( $subscription->get_line_total( $item, false, false ), $decimal_places ), + 'total_tax' => wc_format_decimal( $item['line_tax'], $decimal_places ), + 'taxes' => array(), + 'meta' => $item_meta, + ); + + $item_line_taxes = maybe_unserialize( $item['line_tax_data'] ); + if ( isset( $item_line_taxes['total'] ) ) { + $line_tax = array(); + + foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) { + $line_tax[ $tax_rate_id ] = array( + 'id' => $tax_rate_id, + 'total' => $tax, + 'subtotal' => '', + ); + } + + foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) { + $line_tax[ $tax_rate_id ]['subtotal'] = $tax; + } + + $line_item['taxes'] = array_values( $line_tax ); + } + + $response->data['removed_line_items'][] = $line_item; + } + } + + return $response; + } + + /** + * Sets the order_total value on the subscription after WC_REST_Orders_Controller::create_order + * calls calculate_totals(). This allows store admins to create a recurring payment via the api + * without needing to attach a product to the subscription. + * + * @since 2.1 + * @param WP_REST_Request $request + */ + protected function create_order( $request ) { + try { + if ( ! is_null( $request['customer_id'] ) && 0 !== $request['customer_id'] && false === get_user_by( 'id', $request['customer_id'] ) ) { + throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce-subscriptions' ), 400 ); + } + + // If the start date is not set in the request, set its default to now + if ( ! isset( $request['start_date'] ) ) { + $request['start_date'] = gmdate( 'Y-m-d H:i:s' ); + } + + // prepare all subscription data from the request + $subscription = $this->prepare_item_for_database( $request ); + $subscription->set_created_via( 'rest-api' ); + $subscription->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); + $subscription->calculate_totals(); + + // allow the order total to be overriden (i.e. if you want to have a subscription with no order items but a flat $10.00 recurring payment ) + if ( isset( $request['order_total'] ) ) { + $subscription->set_total( wc_format_decimal( $request['order_total'], get_option( 'woocommerce_price_num_decimals' ) ) ); + } + + // Store the post meta on the subscription after it's saved, this is to avoid compat. issue with the filters in WC_Subscription::set_payment_method_meta() expecting the $subscription to have an ID (therefore it needs to be called after the WC_Subscription has been saved) + $payment_data = ( ! empty( $request['payment_details'] ) ) ? $request['payment_details'] : array(); + if ( empty( $payment_data['payment_details']['method_id'] ) && ! empty( $request['payment_method'] ) ) { + $payment_data['method_id'] = $request['payment_method']; + } + + $this->update_payment_method( $subscription, $payment_data ); + + $subscription->save(); + + // Handle set paid. + if ( true === $request['set_paid'] ) { + $subscription->payment_complete( $request['transaction_id'] ); + } + + do_action( 'wcs_api_subscription_created', $subscription->get_id() ); + + return $subscription->get_id(); + } catch ( WC_Data_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); + } catch ( WC_REST_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Overrides WC_REST_Orders_Controller::update_order to update subscription specific meta + * calls parent::update_order to update the rest. + * + * @since 2.1 + * @param WP_REST_Request $request + * @param WP_POST $post + */ + protected function update_order( $request ) { + try { + $subscription = $this->prepare_item_for_database( $request ); + + // If any line items have changed, recalculate subscription totals. + if ( isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) { + $subscription->calculate_totals(); + } + + // allow the order total to be overriden (i.e. if you want to have a subscription with no order items but a flat $10.00 recurring payment ) + if ( isset( $request['order_total'] ) ) { + $subscription->set_total( wc_format_decimal( $request['order_total'], get_option( 'woocommerce_price_num_decimals' ) ) ); + } + + $subscription->save(); + + // Update the post meta on the subscription after it's saved, this is to avoid compat. issue with the filters in WC_Subscription::set_payment_method_meta() expecting the $subscription to have an ID (therefore it needs to be called after the WC_Subscription has been saved) + $payment_data = ( ! empty( $request['payment_details'] ) ) ? $request['payment_details'] : array(); + $existing_payment_method_id = $subscription->get_payment_method(); + + if ( empty( $payment_data['method_id'] ) && isset( $request['payment_method'] ) ) { + $payment_data['method_id'] = $request['payment_method']; + + } elseif ( ! empty( $existing_payment_method_id ) ) { + $payment_data['method_id'] = $existing_payment_method_id; + } + + if ( isset( $payment_data['method_id'] ) ) { + $this->update_payment_method( $subscription, $payment_data, true ); + } + + // Handle set paid. + if ( $subscription->needs_payment() && true === $request['set_paid'] ) { + $subscription->payment_complete(); + } + + do_action( 'wcs_api_subscription_updated', $subscription->get_id() ); + + return $subscription->get_id(); + } catch ( WC_Data_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); + } catch ( WC_REST_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Get subscription orders + * + * @since 2.1 + * @param WP_REST_Request $request + * @return WP_Error|WP_REST_Response $response + */ + public function get_subscription_orders( $request ) { + $id = (int) $request['id']; + + if ( empty( $id ) || ! wcs_is_subscription( $id ) ) { + return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', __( 'Invalid subscription id.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); + } + + $this->post_type = 'shop_order'; + $subscription = wcs_get_subscription( $id ); + $subscription_orders = $subscription->get_related_orders(); + + $orders = array(); + + foreach ( $subscription_orders as $order_id ) { + $post = get_post( $order_id ); + + // Validate that the order can be loaded before trying to generate a response object for it. + $order = wc_get_order( $order_id ); + + if ( ! $order || ! wc_rest_check_post_permissions( $this->post_type, 'read', $post->ID ) ) { + continue; + } + + $response = $this->prepare_item_for_response( $post, $request ); + + foreach ( array( 'parent', 'renewal', 'switch' ) as $order_type ) { + if ( wcs_order_contains_subscription( $order_id, $order_type ) ) { + $response->data['order_type'] = $order_type . '_order'; + break; + } + } + + $orders[] = $this->prepare_response_for_collection( $response ); + } + + $response = rest_ensure_response( $orders ); + $response->header( 'X-WP-Total', count( $orders ) ); + $response->header( 'X-WP-TotalPages', 1 ); + + return apply_filters( 'wcs_rest_subscription_orders_response', $response, $request ); + } + + /** + * Get subscription statuses + * + * @since 2.1 + */ + public function get_statuses() { + return rest_ensure_response( wcs_get_subscription_statuses() ); + } + + /** + * Overrides WC_REST_Orders_Controller::get_order_statuses() so that subscription statuses are + * validated correctly in WC_REST_Orders_Controller::get_collection_params() + * + * @since 2.1 + */ + protected function get_order_statuses() { + $subscription_statuses = array(); + + foreach ( array_keys( wcs_get_subscription_statuses() ) as $status ) { + $subscription_statuses[] = str_replace( 'wc-', '', $status ); + } + return $subscription_statuses; + } + + /** + * Validate and update payment method on a subscription + * + * @since 2.1 + * @param WC_Subscription $subscription + * @param array $data + * @param bool $updating + */ + public function update_payment_method( $subscription, $data, $updating = false ) { + $payment_method = ( ! empty( $data['method_id'] ) ) ? $data['method_id'] : ''; + + try { + if ( $updating && ! array_key_exists( $payment_method, WCS_Change_Payment_Method_Admin::get_valid_payment_methods( $subscription ) ) ) { + throw new Exception( __( 'Gateway does not support admin changing the payment method on a Subscription.', 'woocommerce-subscriptions' ) ); + } + + $payment_method_meta = apply_filters( 'woocommerce_subscription_payment_meta', array(), $subscription ); + + // Reload the subscription to update the meta values. + // In particular, the update_post_meta() called while _stripe_card_id is updated to _stripe_source_id + $subscription = wcs_get_subscription( $subscription->get_id() ); + + if ( isset( $payment_method_meta[ $payment_method ] ) ) { + $payment_method_meta = $payment_method_meta[ $payment_method ]; + + if ( ! empty( $payment_method_meta ) ) { + + foreach ( $payment_method_meta as $meta_table => &$meta ) { + if ( ! is_array( $meta ) ) { + continue; + } + + foreach ( $meta as $meta_key => &$meta_data ) { + + if ( isset( $data[ $meta_table ][ $meta_key ] ) ) { + $meta_data['value'] = $data[ $meta_table ][ $meta_key ]; + } + } + } + } + } + + $subscription->set_payment_method( $payment_method, $payment_method_meta ); + + // Save the subscription to reflect the new values + $subscription->save(); + + } catch ( Exception $e ) { + $subscription->set_payment_method(); + $subscription->save(); + // translators: 1$: gateway id, 2$: error message + throw new WC_REST_Exception( 'woocommerce_rest_invalid_payment_data', sprintf( __( 'Subscription payment method could not be set to %1$s with error message: %2$s', 'woocommerce-subscriptions' ), $payment_method, $e->getMessage() ), 400 ); + } + } + + /** + * Prepare a single subscription for create. + * + * @param WP_REST_Request $request Request object. + * @return WP_Error|WC_Subscription $data Object. + */ + protected function prepare_item_for_database( $request ) { + $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; + $subscription = new WC_Subscription( $id ); + $schema = $this->get_item_schema(); + $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); + + $dates_to_update = array(); + + // Handle all writable props + foreach ( $data_keys as $key ) { + $value = $request[ $key ]; + + if ( ! is_null( $value ) ) { + switch ( $key ) { + case 'billing': + case 'shipping': + $this->update_address( $subscription, $value, $key ); + break; + case 'line_items': + case 'shipping_lines': + case 'fee_lines': + case 'coupon_lines': + if ( is_array( $value ) ) { + foreach ( $value as $item ) { + if ( is_array( $item ) ) { + if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { + $subscription->remove_item( $item['id'] ); + } else { + $this->set_item( $subscription, $key, $item ); + } + } + } + } + break; + case 'transition_status': + $subscription->update_status( $value ); + break; + case 'start_date': + case 'trial_end_date': + case 'next_payment_date': + case 'end_date': + $dates_to_update[ $key ] = $value; + break; + default: + if ( is_callable( array( $subscription, "set_{$key}" ) ) ) { + $subscription->{"set_{$key}"}( $value ); + } + break; + } + } + } + + $subscription->save(); + + try { + if ( ! empty( $dates_to_update ) ) { + $subscription->update_dates( $dates_to_update ); + } + } catch ( Exception $e ) { + // translators: placeholder is an error message. + throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_subscription_dates', sprintf( __( 'Updating subscription dates errored with message: %s', 'woocommerce-subscriptions' ), $e->getMessage() ), 400 ); + } + + /** + * Filter the data for the insert. + * + * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being + * prepared for the response. + * + * @param WC_Subscription $subscription The subscription object. + * @param WP_REST_Request $request Request object. + */ + return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $subscription, $request ); + } + + /** + * Adds additional item schema information for subscription requests + * + * @since 2.1 + */ + public function get_item_schema() { + $schema = parent::get_item_schema(); + + $subscriptions_schema = array( + 'transition_status' => array( + 'description' => __( 'The status to transition the subscription to. Unlike the "status" param, this will calculate and update the subscription dates.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'enum' => $this->get_order_statuses(), + 'context' => array( 'edit' ), + ), + 'billing_interval' => array( + 'description' => __( 'The number of billing periods between subscription renewals.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'billing_period' => array( + 'description' => __( 'Billing period for the subscription.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'enum' => array_keys( wcs_get_subscription_period_strings() ), + 'context' => array( 'view', 'edit' ), + ), + 'payment_details' => array( + 'description' => __( 'Subscription payment details.', 'woocommerce-subscriptions' ), + 'type' => 'object', + 'context' => array( 'edit' ), + 'properties' => array( + 'method_id' => array( + 'description' => __( 'Payment gateway ID.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'edit' ), + ), + ), + ), + 'start_date' => array( + 'description' => __( "The subscription's start date.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'trial_end_date' => array( + 'description' => __( "The subscription's trial date", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'next_payment_date' => array( + 'description' => __( "The subscription's next payment date.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'end_date' => array( + 'description' => __( "The subscription's end date.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'resubscribed_from' => array( + 'description' => __( "The subscription's original subscription ID if this is a resubscribed subscription.", 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'resubscribed_subscription' => array( + 'description' => __( "The subscription's resubscribed subscription ID.", 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'date_completed_gmt' => array( + 'description' => __( "The date the subscription's latest order was completed, in GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'date_paid_gmt' => array( + 'description' => __( "The date the subscription's latest order was paid, in GMT.", 'woocommerce-subscriptions' ), + 'type' => 'date-time', + 'context' => array( 'view' ), + 'readonly' => true, + ), + 'removed_line_items' => array( + 'description' => __( 'Removed line items data.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'Item ID.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'name' => array( + 'description' => __( 'Product name.', 'woocommerce-subscriptions' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'sku' => array( + 'description' => __( 'Product SKU.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'product_id' => array( + 'description' => __( 'Product ID.', 'woocommerce-subscriptions' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + 'variation_id' => array( + 'description' => __( 'Variation ID, if applicable.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'quantity' => array( + 'description' => __( 'Quantity ordered.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'tax_class' => array( + 'description' => __( 'Tax class of product.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'price' => array( + 'description' => __( 'Product price.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'subtotal' => array( + 'description' => __( 'Line subtotal (before discounts).', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'subtotal_tax' => array( + 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'total' => array( + 'description' => __( 'Line total (after discounts).', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'total_tax' => array( + 'description' => __( 'Line total tax (after discounts).', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'taxes' => array( + 'description' => __( 'Line taxes.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'Tax rate ID.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total' => array( + 'description' => __( 'Tax total.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'subtotal' => array( + 'description' => __( 'Tax subtotal.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ), + ), + 'meta' => array( + 'description' => __( 'Removed line item meta data.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'key' => array( + 'description' => __( 'Meta key.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'label' => array( + 'description' => __( 'Meta label.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'value' => array( + 'description' => __( 'Meta value.', 'woocommerce-subscriptions' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ), + ), + ), + ), + ), + ); + + $schema['properties'] += $subscriptions_schema; + return $schema; + } + + /** + * Deprecated functions + */ + + /** + * Prepare subscription data for create. + * + * Now that we override WC_REST_Orders_V1_Controller::prepare_item_for_database() function, + * we no longer need to prepare these args + * + * @since 2.1 + * @param stdClass $data + * @param WP_REST_Request $request Request object. + * @return stdClass + * @deprecated 2.2 + */ + public function prepare_subscription_args( $data, $request ) { + wcs_deprecated_function( __METHOD__, '2.2' ); + + $data->billing_interval = $request['billing_interval']; + $data->billing_period = $request['billing_period']; + + foreach ( array( 'start', 'trial_end', 'end', 'next_payment' ) as $date_type ) { + if ( ! empty( $request[ $date_type . '_date' ] ) ) { + $date_type_key = ( 'start' === $date_type ) ? 'date_created' : $date_type . '_date'; + $data->{$date_type_key} = $request[ $date_type . '_date' ]; + } + } + + $data->payment_details = ! empty( $request['payment_details'] ) ? $request['payment_details'] : ''; + $data->payment_method = ! empty( $request['payment_method'] ) ? $request['payment_method'] : ''; + + return $data; + } + + /** + * Update or set the subscription schedule with the request data. + * + * + * @since 2.1 + * @param WC_Subscription $subscription + * @param array $data + * @deprecated 2.2 + */ + public function update_schedule( $subscription, $data ) { + wcs_deprecated_function( __METHOD__, '2.2', 'WC_REST_Subscriptions_Controller::prepare_item_for_database() now prepares the billing interval/period and dates' ); + + if ( isset( $data['billing_interval'] ) ) { + $subscription->set_billing_interval( absint( $data['billing_interval'] ) ); + } + + if ( ! empty( $data['billing_period'] ) ) { + $subscription->set_billing_period( $data['billing_period'] ); + } + + try { + $dates_to_update = array(); + + foreach ( array( 'start', 'trial_end', 'end', 'next_payment' ) as $date_type ) { + if ( isset( $data[ $date_type . '_date' ] ) ) { + $date_type_key = ( 'start' === $date_type ) ? 'date_created' : $date_type; + $dates_to_update[ $date_type_key ] = $data[ $date_type . '_date' ]; + } + } + + if ( ! empty( $dates_to_update ) ) { + $subscription->update_dates( $dates_to_update ); + } + } catch ( Exception $e ) { + // translators: placeholder is an error message. + throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_subscription_dates', sprintf( __( 'Updating subscription dates errored with message: %s', 'woocommerce-subscriptions' ), $e->getMessage() ), 400 ); + } + } +} diff --git a/includes/class-wc-subscriptions-plugin.php b/includes/class-wc-subscriptions-plugin.php new file mode 100644 index 0000000..f77c24e --- /dev/null +++ b/includes/class-wc-subscriptions-plugin.php @@ -0,0 +1,223 @@ + tags, 3: Subscriptions version. + $notice->set_simple_content( sprintf( __( '%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce Subscriptions%2$s comes with that plugin\'s functionality packaged into the core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to avoid any conflicts.', 'woocommerce-subscriptions' ), '', '', $this->get_plugin_version() ) ); + $notice->set_actions( + array( + array( + 'name' => __( 'Installed Plugins', 'woocommerce-subscriptions' ), + 'url' => admin_url( 'plugins.php' ), + ), + ) + ); + + $notice->display(); + } else { + WCS_Early_Renewal_Manager::init(); + + require_once $this->get_plugin_directory( 'includes/early-renewal/wcs-early-renewal-functions.php' ); + + if ( WCS_Early_Renewal_Manager::is_early_renewal_enabled() ) { + new WCS_Cart_Early_Renewal(); + } + } + } + + /** + * Gets the plugin's directory url. + * + * @since 4.0.0 + * @param string $path Optional. The path to append. + * @return string + */ + public function get_plugin_directory_url( $path = '' ) { + return plugin_dir_url( WC_Subscriptions::$plugin_file ) . $path; + } + + /** + * Gets the plugin's directory. + * + * @since 4.0.0 + * @param string $path Optional. The path to append. + * @return string + */ + public function get_plugin_directory( $path = '' ) { + return plugin_dir_path( WC_Subscriptions::$plugin_file ) . $path; + } + + /** + * Gets the activation transient name. + * + * @since 4.0.0 + * @return string The transient name used to record when the plugin was activated. + */ + public function get_activation_transient() { + return WC_Subscriptions::$activation_transient; + } + + /** + * Gets the product type name. + * + * @since 4.0.0 + * @return string The product type name. + */ + public function get_product_type_name() { + return WC_Subscriptions::$name; + } + + /** + * Gets the plugin's version + * + * @since 4.0.0 + * @return string The plugin version. + */ + public function get_plugin_version() { + return WC_Subscriptions::$version; + } + + /** + * Gets the plugin file name + * + * @since 4.0.0 + * @return string The plugin file + */ + public function get_plugin_file() { + return WC_Subscriptions::$plugin_file; + } + + /** + * Gets the Payment Gateways handler class + * + * @since 4.0.0 + * @return string + */ + public function get_gateways_handler_class() { + return 'WC_Subscriptions_Payment_Gateways'; + } + + + /** + * Adds welcome message after activating the plugin + */ + public function maybe_show_welcome_message() { + $plugin_has_just_been_activated = (bool) get_transient( WC_Subscriptions_Core_Plugin::instance()->get_activation_transient() ); + + // Maybe add the admin notice. + if ( $plugin_has_just_been_activated ) { + + $woocommerce_plugin_dir_file = WC_Subscriptions_Admin::get_woocommerce_plugin_dir_file(); + + // check if subscription products exist in the store. + $subscription_product = wc_get_products( + array( + 'type' => array( 'subscription', 'variable-subscription' ), + 'limit' => 1, + 'return' => 'ids', + ) + ); + + if ( ! empty( $woocommerce_plugin_dir_file ) && 0 === count( $subscription_product ) ) { + + wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', $woocommerce_plugin_dir_file ), [], WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() ); + + if ( ! isset( $_GET['page'] ) || 'wcs-about' !== $_GET['page'] ) { + add_action( 'admin_notices', array( $this, 'admin_installed_notice' ) ); + } + } + delete_transient( WC_Subscriptions_Core_Plugin::instance()->get_activation_transient() ); + } + } + + /** + * Outputs a welcome message. Called when the Subscriptions extension is activated. + * + * @since 1.0 + */ + public function admin_installed_notice() { + ?> +
    +
    +

    + tags, $3-$4: opening and closing tags. + __( + '%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou\'re ready to start selling subscriptions!%4$s', + 'woocommerce-subscriptions' + ), + '', + '', + '', + '' + ), + [ + 'strong' => true, + 'em' => true, + ] + ); + ?> +

    + +

    + + + + +

    +
    +
    + register_routes(); } } + /** + * Register classes which override base endpoints. + * + * @since 3.1.0 + */ + public static function register_route_overrides() { + if ( ! self::is_wp_compatible() ) { + return; + } + + WC_REST_Subscription_System_Status_Manager::init(); + } + + /** + * Determines if a WP version compatible with REST API requests. + * + * @since 3.1.0 + * @return boolean + */ + protected static function is_wp_compatible() { + global $wp_version; + return version_compare( $wp_version, '4.4', '>=' ); + } } diff --git a/includes/class-wcs-autoloader.php b/includes/class-wcs-autoloader.php index 01097b1..940921b 100644 --- a/includes/class-wcs-autoloader.php +++ b/includes/class-wcs-autoloader.php @@ -1,23 +1,14 @@ base_path = untrailingslashit( $base_path ); - } + private $classes = array( + 'wc_subscriptions_plugin' => true, + 'wc_subscriptions_switcher' => true, + 'wcs_cart_switch' => true, + 'wcs_switch_totals_calculator' => true, + 'wcs_switch_cart_item' => true, + 'wcs_add_cart_item' => true, + 'wc_order_item_pending_switch' => true, + 'wcs_manual_renewal_manager' => true, + 'wcs_customer_suspension_manager' => true, + 'wcs_drip_downloads_manager' => true, + 'wcs_zero_initial_payment_checkout_manager' => true, + 'wcs_meta_box_payment_retries' => true, + 'wcs_limited_recurring_coupon_manager' => true, + 'wcs_call_to_action_button_text_manager' => true, + 'wcs_subscriber_role_manager' => true, + 'wc_subscriptions_payment_gateways' => true, + 'wcs_api' => true, + 'wcs_webhooks' => true, + 'wcs_auth' => true, + 'wcs_upgrade_notice_manager' => true, + ); /** - * Destructor. + * The substrings of the classes that the Subscriptions plugin has ownership of. + * + * @var array */ - public function __destruct() { - $this->unregister(); - } + private $class_substrings = array( + 'wc_reports', + 'report', + 'retry', + 'early_renewal', + 'rest_subscription', + 'wc_api_subscriptions', + ); /** - * Register the autoloader. + * Gets the class's base path. * - * @author Jeremy Pry - */ - public function register() { - spl_autoload_register( array( $this, 'autoload' ) ); - } - - /** - * Unregister the autoloader. - */ - public function unregister() { - spl_autoload_unregister( array( $this, 'autoload' ) ); - } - - /** - * Autoload a class. + * If the a class is one the plugin is responsible for, we return the plugin's path. Otherwise we let the library handle it. * - * @author Jeremy Pry - * - * @param string $class The class name to autoload. + * @since 4.0.0 + * @return string */ - public function autoload( $class ) { - $class = strtolower( $class ); - - if ( ! $this->should_autoload( $class ) ) { - return; + public function get_class_base_path( $class ) { + if ( $this->is_plugin_class( $class ) ) { + return dirname( WC_Subscriptions::$plugin_file ); } - $full_path = $this->base_path . $this->get_relative_class_path( $class ) . $this->get_file_name( $class ); - if ( is_readable( $full_path ) ) { - require_once( $full_path ); - } - } - - /** - * Determine whether we should autoload a given class. - * - * @author Jeremy Pry - * - * @param string $class The class name. - * - * @return bool - */ - protected function should_autoload( $class ) { - // We're not using namespaces, so if the class has namespace separators, skip. - if ( false !== strpos( $class, '\\' ) ) { - return false; - } - - // There are some legacy classes without WCS or Subscription in the name. - static $legacy = array( - 'wc_order_item_pending_switch' => 1, - 'wc_report_retention_rate' => 1, - 'wc_report_upcoming_recurring_revenue' => 1, - ); - if ( isset( $legacy[ $class ] ) ) { - return true; - } - - return false !== strpos( $class, 'wcs_' ) || 0 === strpos( $class, 'wc_subscription' ) || ( false !== strpos( $class, 'wc_' ) && false !== strpos( $class, 'subscription' ) ); - } - - /** - * Convert the class name into an appropriate file name. - * - * @author Jeremy Pry - * - * @param string $class The class name. - * - * @return string The file name. - */ - protected function get_file_name( $class ) { - $file_prefix = 'class-'; - - if ( $this->is_class_abstract( $class ) ) { - $file_prefix = 'abstract-'; - } elseif ( $this->is_class_interface( $class ) ) { - $file_prefix = 'interface-'; - } - - return $file_prefix . str_replace( '_', '-', $class ) . '.php'; - } - - /** - * Determine if the class is one of our abstract classes. - * - * @author Jeremy Pry - * - * @param string $class The class name. - * - * @return bool - */ - protected function is_class_abstract( $class ) { - static $abstracts = array( - 'wcs_background_repairer' => true, - 'wcs_background_updater' => true, - 'wcs_background_upgrader' => true, - 'wcs_cache_manager' => true, - 'wcs_debug_tool' => true, - 'wcs_debug_tool_cache_updater' => true, - 'wcs_dynamic_hook_deprecator' => true, - 'wcs_hook_deprecator' => true, - 'wcs_retry_store' => true, - 'wcs_scheduler' => true, - 'wcs_sv_api_base' => true, - 'wcs_customer_store' => true, - 'wcs_related_order_store' => true, - 'wcs_migrator' => true, - 'wcs_table_maker' => true, - ); - - return isset( $abstracts[ $class ] ); - } - - /** - * Determine if the class is one of our class interfaces. - * - * @param string $class The class name. - - * @return bool - */ - protected function is_class_interface( $class ) { - static $interfaces = array( - 'wcs_cache_updater' => true, - ); - - return isset( $interfaces[ $class ] ); - } - - /** - * Determine if the class is one of our data stores. - * - * @param string $class The class name. - - * @return bool - */ - protected function is_class_data_store( $class ) { - static $data_stores = array( - 'wcs_related_order_store_cached_cpt' => true, - 'wcs_related_order_store_cpt' => true, - 'wcs_customer_store_cached_cpt' => true, - 'wcs_customer_store_cpt' => true, - 'wcs_product_variable_data_store_cpt' => true, - 'wcs_subscription_data_store_cpt' => true, - ); - - return isset( $data_stores[ $class ] ); + return parent::get_class_base_path( $class ); } /** * Get the relative path for the class location. * - * This handles all of the special class locations and exceptions. - * - * @author Jeremy Pry - * * @param string $class The class name. - * * @return string The relative path (from the plugin root) to the class file. */ protected function get_relative_class_path( $class ) { - $path = '/includes'; - $is_admin = ( false !== strpos( $class, 'admin' ) ); + if ( ! $this->is_plugin_class( $class ) ) { + return parent::get_relative_class_path( $class ); + } - if ( $this->is_class_abstract( $class ) ) { - if ( 'wcs_sv_api_base' === $class ) { - $path .= '/gateways/paypal/includes/abstracts'; - } else { - $path .= '/abstracts'; - } - } elseif ( $this->is_class_interface( $class ) ) { - $path .= '/interfaces'; - } elseif ( false !== strpos( $class, 'paypal' ) ) { - $path .= '/gateways/paypal'; - if ( 'wcs_paypal' === $class ) { - $path .= ''; - } elseif ( 'wcs_repair_suspended_paypal_subscriptions' === $class ) { - // Deliberately avoid concatenation for this class, using the base path. - $path = '/includes/upgrades'; - } elseif ( $is_admin ) { - $path .= '/includes/admin'; - } elseif ( 'wc_paypal_standard_subscriptions' === $class ) { - $path .= '/includes/deprecated'; - } else { - $path .= '/includes'; - } - } elseif ( 0 === strpos( $class, 'wcs_retry' ) && 'wcs_retry_manager' !== $class ) { - $path .= '/payment-retry'; - } elseif ( $is_admin && 'wcs_change_payment_method_admin' !== $class ) { - $path .= '/admin'; - } elseif ( false !== strpos( $class, 'meta_box' ) ) { - $path .= '/admin/meta-boxes'; + $path = '/includes'; + + if ( stripos( $class, 'switch' ) !== false || 'wcs_add_cart_item' === $class ) { + $path .= '/switching'; } elseif ( false !== strpos( $class, 'wc_report' ) ) { $path .= '/admin/reports/deprecated'; - } elseif ( false !== strpos( $class, 'report' ) ) { + } elseif ( false !== strpos( $class, 'wcs_report' ) ) { $path .= '/admin/reports'; - } elseif ( false !== strpos( $class, 'debug_tool' ) ) { - $path .= '/admin/debug-tools'; - } elseif ( false !== strpos( $class, 'rest' ) ) { - $path .= $this->legacy_api ? '/api/legacy' : '/api'; - } elseif ( false !== strpos( $class, 'api' ) && 'wcs_api' !== $class ) { - $path .= '/api/legacy'; - } elseif ( $this->is_class_data_store( $class ) ) { - $path .= '/data-stores'; - } elseif ( false !== strpos( $class, 'deprecat' ) ) { - $path .= '/deprecated'; - } elseif ( false !== strpos( $class, 'email' ) && 'wc_subscriptions_email' !== $class ) { - $path .= '/emails'; - } elseif ( false !== strpos( $class, 'gateway' ) && 'wc_subscriptions_change_payment_gateway' !== $class ) { - $path .= '/gateways'; - } elseif ( false !== strpos( $class, 'legacy' ) || 'wcs_array_property_post_meta_black_magic' === $class ) { - $path .= '/legacy'; - } elseif ( false !== strpos( $class, 'privacy' ) ) { - $path .= '/privacy'; - } elseif ( false !== strpos( $class, 'upgrade' ) || false !== strpos( $class, 'repair' ) ) { - $path .= '/upgrades'; + } elseif ( false !== strpos( $class, 'retry' ) || false !== strpos( $class, 'retries' ) ) { + $path .= $this->get_payment_retry_class_relative_path( $class ); + } elseif ( false !== strpos( $class, 'admin' ) ) { + $path .= '/admin'; } elseif ( false !== strpos( $class, 'early' ) ) { $path .= '/early-renewal'; + } elseif ( false !== strpos( $class, 'gateways' ) ) { + $path .= '/gateways'; + } elseif ( false !== strpos( $class, 'rest' ) ) { + $path .= $this->legacy_api ? '/api/legacy' : $this->get_rest_api_directory( $class ); + } elseif ( false !== strpos( $class, 'api' ) && 'wcs_api' !== $class ) { + $path .= '/api/legacy'; } return trailingslashit( $path ); } + /** + * Determine whether we should autoload a given class. + * + * @param string $class The class name. + * @return bool + */ + protected function should_autoload( $class ) { + static $legacy = array( + 'wc_order_item_pending_switch' => 1, + 'wc_report_retention_rate' => 1, + 'wc_report_upcoming_recurring_revenue' => 1, + ); + + return isset( $legacy[ $class ] ) ? true : parent::should_autoload( $class ); + + } + + /** + * Is the given class found in the Subscriptions plugin + * + * @since 4.0.0 + * @param string $class + * @return bool + */ + private function is_plugin_class( $class ) { + if ( isset( $this->classes[ $class ] ) ) { + return true; + } + + foreach ( $this->class_substrings as $substring ) { + if ( false !== stripos( $class, $substring ) ) { + return true; + } + } + + return false; + } + + /** + * Gets a retry class's relative path. + * + * @param string $class The retry class being loaded. + * @return string The relative path to the retry class. + */ + private function get_payment_retry_class_relative_path( $class ) { + $relative_path = '/payment-retry'; + + if ( false !== strpos( $class, 'admin' ) || false !== strpos( $class, 'meta_box' ) ) { + $relative_path .= '/admin'; + } elseif ( false !== strpos( $class, 'email' ) ) { + $relative_path .= '/emails'; + } elseif ( false !== strpos( $class, 'store' ) ) { + $relative_path .= '/data-stores'; + } + + return $relative_path; + } + + /** + * Determine if the class is one of our abstract classes. + * + * @param string $class The class name. + * @return bool + */ + protected function is_class_abstract( $class ) { + static $abstracts = array( + 'wcs_retry_store' => true, + ); + + return isset( $abstracts[ $class ] ) || parent::is_class_abstract( $class ); + } + /** * Set whether the legacy API should be used. * @@ -281,4 +199,23 @@ class WCS_Autoloader { return $this; } + + /** + * Gets the correct subdirectory for a version of the a REST API class. + * + * @param string $class The rest API class name. + * @return string The subdirectory for a rest API class. + */ + protected function get_rest_api_directory( $class ) { + $directory = '/api'; + + // Check for an API version in the class name. + preg_match( '/v\d/', $class, $matches ); + + if ( ! empty( $matches ) ) { + $directory .= "/{$matches[0]}"; + } + + return $directory; + } } diff --git a/includes/class-wcs-call-to-action-button-text-manager.php b/includes/class-wcs-call-to-action-button-text-manager.php new file mode 100644 index 0000000..ed80e6a --- /dev/null +++ b/includes/class-wcs-call-to-action-button-text-manager.php @@ -0,0 +1,94 @@ + __( 'Button Text', 'woocommerce-subscriptions' ), + 'type' => 'title', + 'desc' => '', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_button_text', + ), + array( + 'name' => __( 'Add to Cart Button Text', 'woocommerce-subscriptions' ), + 'desc' => __( 'A product displays a button with the text "Add to cart". By default, a subscription changes this to "Sign up now". You can customise the button text for subscriptions here.', 'woocommerce-subscriptions' ), + 'tip' => '', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text', + 'css' => 'min-width:150px;', + 'default' => __( 'Sign up now', 'woocommerce-subscriptions' ), + 'type' => 'text', + 'desc_tip' => true, + 'placeholder' => __( 'Sign up now', 'woocommerce-subscriptions' ), + ), + array( + 'name' => __( 'Place Order Button Text', 'woocommerce-subscriptions' ), + 'desc' => __( 'Use this field to customise the text displayed on the checkout button when an order contains a subscription. Normally the checkout submission button displays "Place order". When the cart contains a subscription, this is changed to "Sign up now".', 'woocommerce-subscriptions' ), + 'tip' => '', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_order_button_text', + 'css' => 'min-width:150px;', + 'default' => __( 'Sign up now', 'woocommerce-subscriptions' ), + 'type' => 'text', + 'desc_tip' => true, + 'placeholder' => __( 'Sign up now', 'woocommerce-subscriptions' ), + ), + array( + 'type' => 'sectionend', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_button_text', + ), + ); + + return array_merge( $button_text_settings, $settings ); + } + + /** + * Filters subscription products add to cart text to honour the setting. + * + * @since 4.0.0 + * + * @param string $add_to_cart_text The product's add to cart text. + * @param WC_Abstract_Product $product The product. + * + * @return string + */ + public static function filter_add_to_cart_text( $add_to_cart_text ) { + return get_option( WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text', $add_to_cart_text ); + } + + /** + * Filters the place order text while there's a subscription in the cart. + * + * @since 4.0.0 + * + * @param string $button_text The default place order button text. + * @return string The button text. + */ + public static function filter_place_subscription_order_text( $button_text ) { + return get_option( WC_Subscriptions_Admin::$option_prefix . '_order_button_text', $button_text ); + } +} diff --git a/includes/class-wcs-customer-suspension-manager.php b/includes/class-wcs-customer-suspension-manager.php new file mode 100644 index 0000000..3b7b8f0 --- /dev/null +++ b/includes/class-wcs-customer-suspension-manager.php @@ -0,0 +1,126 @@ + __( 'Customer Suspensions', 'woocommerce-subscriptions' ), + 'desc' => _x( 'suspensions per billing period.', 'there\'s a number immediately in front of this text', 'woocommerce-subscriptions' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions', + 'css' => 'min-width:50px;', + 'default' => 0, + 'type' => 'select', + 'options' => apply_filters( 'woocommerce_subscriptions_max_customer_suspension_range', array_merge( range( 0, 12 ), array( 'unlimited' => 'Unlimited' ) ) ), + 'desc_tip' => __( 'Set a maximum number of times a customer can suspend their account for each billing period. For example, for a value of 3 and a subscription billed yearly, if the customer has suspended their account 3 times, they will not be presented with the option to suspend their account until the next year. Store managers will always be able to suspend an active subscription. Set this to 0 to turn off the customer suspension feature completely.', 'woocommerce-subscriptions' ), + ); + + WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $suspension_setting ); + return $settings; + } + + /** + * Filters whether the current user can suspend the subscription. + * + * Allows the customer to suspend the subscription if the _max_customer_suspensions setting hasn't been reached. + * + * @since 4.0.0 + * + * @param bool $can_user_suspend Whether the current user can suspend the subscrption determined by @see wcs_can_user_put_subscription_on_hold(). + * @param WC_Subscription $subscription The subscription. + * @param WP_User $user The current user. + * + * @return bool Whether the subscription can be suspended by the user. + */ + public static function can_customer_put_subscription_on_hold( $can_user_suspend, $subscription, $user ) { + + // Exit early if the customer can already suspend the subscription. + if ( $can_user_suspend ) { + return $can_user_suspend; + } + + // We're only interested in the customer who owns the subscription. + if ( $subscription->get_user_id() !== $user->ID ) { + return $can_user_suspend; + } + + // Make sure subscription suspension count hasn't been reached + $suspension_count = intval( $subscription->get_suspension_count() ); + $allowed_suspensions = self::get_allowed_customer_suspensions(); + + if ( 'unlimited' === $allowed_suspensions || $allowed_suspensions > $suspension_count ) { // 0 not > anything so prevents a customer ever being able to suspend + $can_user_suspend = true; + } + + return $can_user_suspend; + } + + /** + * Adds the customer suspension action, if allowed. + * + * @since 4.0.0 + * + * @param array $actions The actions a customer/user can make with a subscription. + * @param WC_Subscription $subscription The subscription. + * @param int $user_id The user viewing the subscription. + * + * @return array The customer's subscription actions. + */ + public static function add_customer_suspension_action( $actions, $subscription, $user_id ) { + + if ( ! $subscription->can_be_updated_to( 'on-hold' ) ) { + return $actions; + } + + if ( ! user_can( $user_id, 'edit_shop_subscription_status', $subscription->get_id() ) ) { + return $actions; + } + + if ( '0' === self::get_allowed_customer_suspensions() ) { + return $actions; + } + + if ( current_user_can( 'manage_woocommerce' ) || wcs_can_user_put_subscription_on_hold( $subscription, $user_id ) ) { + $actions['suspend'] = array( + 'url' => wcs_get_users_change_status_link( $subscription->get_id(), 'on-hold', $subscription->get_status() ), + 'name' => __( 'Suspend', 'woocommerce-subscriptions' ), + ); + } + + return $actions; + } + + /** + * Gets the number of suspensions a customer can make per billing period. + * + * @since 4.0.0 + * @return string The number of suspensions a customer can make per billing period. Can 'unlimited' or the number of suspensions allowed. + */ + public static function get_allowed_customer_suspensions() { + return get_option( WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions', '0' ); + } +} diff --git a/includes/class-wcs-drip-downloads-manager.php b/includes/class-wcs-drip-downloads-manager.php new file mode 100644 index 0000000..43eec3b --- /dev/null +++ b/includes/class-wcs-drip-downloads-manager.php @@ -0,0 +1,76 @@ +get_id() ) || wcs_order_contains_subscription( $order, 'any' ) ) ) { + $grant_access = false; + } + + return $grant_access; + } + + /** + * Adds the Drip Downloadable Content setting. + * + * @since 4.0.0 + * + * @param array $settings The WC Subscriptions settings array. + * @return array Settings. + */ + public static function add_setting( $settings ) { + $setting = array( + 'name' => __( 'Drip Downloadable Content', 'woocommerce-subscriptions' ), + 'desc' => __( 'Enable dripping for downloadable content on subscription products.', 'woocommerce-subscriptions' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_drip_downloadable_content_on_renewal', + 'default' => 'no', + 'type' => 'checkbox', + // translators: %s is a line break. + 'desc_tip' => sprintf( __( 'Enabling this grants access to new downloadable files added to a product only after the next renewal is processed.%sBy default, access to new downloadable files added to a product is granted immediately to any customer that has an active subscription with that product.', 'woocommerce-subscriptions' ), '
    ' ), + ); + + WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $setting ); + return $settings; + } +} diff --git a/includes/class-wcs-limited-recurring-coupon-manager.php b/includes/class-wcs-limited-recurring-coupon-manager.php new file mode 100644 index 0000000..ffa5ae5 --- /dev/null +++ b/includes/class-wcs-limited-recurring-coupon-manager.php @@ -0,0 +1,415 @@ + 'wcs_number_payments', + 'label' => __( 'Active for x payments', 'woocommerce-subscriptions' ), + 'placeholder' => __( 'Unlimited payments', 'woocommerce-subscriptions' ), + 'description' => __( 'Coupon will be limited to the given number of payments. It will then be automatically removed from the subscription. "Payments" also includes the initial subscription payment.', 'woocommerce-subscriptions' ), + 'desc_tip' => true, + 'data_type' => 'decimal', + 'value' => $coupon->get_meta( self::$coupons_renewals ), + ) ); + } + + /** + * Saves our custom coupon fields. + * + * @since 4.0.0 + * @param int $id The coupon's ID. + */ + public static function save_coupon_fields( $id ) { + // Check the nonce (again). + if ( empty( $_POST['woocommerce_meta_nonce'] ) || ! wp_verify_nonce( $_POST['woocommerce_meta_nonce'], 'woocommerce_save_data' ) ) { + return; + } + + $coupon = new WC_Coupon( $id ); + $coupon->add_meta_data( self::$coupons_renewals, wc_clean( $_POST['wcs_number_payments'] ), true ); + $coupon->save(); + } + + /** + * Get the number of renewals for a limited coupon. + * + * @since 4.0.0 + * @param string $code The coupon code. + * @return false|int False for non-recurring coupons, or the limit number for recurring coupons. + * A value of 0 is for unlimited usage. + */ + public static function get_coupon_limit( $code ) { + if ( wcs_is_woocommerce_pre( '3.2' ) ) { + return false; + } + + // Retrieve the coupon data. + $coupon = new WC_Coupon( $code ); + $coupon_type = $coupon->get_discount_type(); + + // If we have a virtual coupon, attempt to get the original coupon. + if ( WC_Subscriptions_Coupon::is_renewal_cart_coupon( $coupon_type ) ) { + $coupon = WC_Subscriptions_Coupon::map_virtual_coupon( $code ); + $coupon_type = $coupon->get_discount_type(); + } + + $limited = $coupon->get_meta( self::$coupons_renewals ); + + return WC_Subscriptions_Coupon::is_recurring_coupon( $coupon_type ) ? intval( $limited ) : false; + } + + /** + * Determines if a given coupon is limited to a certain number of renewals. + * + * @since 4.0.0 + * + * @param string $code The coupon code. + * @return bool + */ + public static function coupon_is_limited( $code ) { + return (bool) self::get_coupon_limit( $code ); + } + + /** + * Determines whether the cart contains a recurring coupon with set number of renewals. + * + * @since 4.0.0 + * @return bool Whether the cart contains a limited recurring coupon. + */ + public static function cart_contains_limited_recurring_coupon() { + $has_coupon = false; + $applied_coupons = isset( WC()->cart->applied_coupons ) ? WC()->cart->applied_coupons : array(); + + foreach ( $applied_coupons as $code ) { + if ( self::coupon_is_limited( $code ) ) { + $has_coupon = true; + break; + } + } + + return $has_coupon; + } + + /** + * Determines if a given order has a limited use coupon. + * + * @since 4.0.0 + * @param WC_Order|WC_Subscription $order + * + * @return bool Whether the order contains a limited recurring coupon. + */ + public static function order_has_limited_recurring_coupon( $order ) { + $has_coupon = false; + + foreach ( wcs_get_used_coupon_codes( $order ) as $code ) { + if ( self::coupon_is_limited( $code ) ) { + $has_coupon = true; + break; + } + } + + return $has_coupon; + } + + /** + * Limits payment gateways to those that support changing subscription amounts. + * + * @since 4.0.0 + * @param WC_Payment_Gateway[] $gateways The current available gateways. + * @return WC_Payment_Gateway[] + */ + private static function limit_gateways_subscription_amount_changes( $gateways ) { + foreach ( $gateways as $index => $gateway ) { + if ( $gateway->supports( 'subscriptions' ) && ! $gateway->supports( 'subscription_amount_changes' ) ) { + unset( $gateways[ $index ] ); + } + } + + return $gateways; + } + + /** + * Determines how many subscription renewals the coupon has been applied to and removes coupons which have reached their expiry. + * + * @since 4.0.0 + * @param WC_Subscription $subscription The current subscription. + */ + public static function check_coupon_usages( $subscription ) { + // If there aren't any coupons, there's nothing to do. + $coupons = wcs_get_used_coupon_codes( $subscription ); + if ( empty( $coupons ) ) { + return; + } + + // Set up the coupons we're looking for, and an initial count. + $limited_coupons = array(); + foreach ( $coupons as $code ) { + if ( self::coupon_is_limited( $code ) ) { + $limited_coupons[ $code ] = array( + 'code' => $code, + 'count' => 0, + ); + } + } + + // Don't continue if we have no limited use coupons. + if ( empty( $limited_coupons ) ) { + return; + } + + // Get all related orders, and count the number of uses for each coupon. + $related = $subscription->get_related_orders( 'all' ); + + /** @var WC_Order $order */ + foreach ( $related as $id => $order ) { + // Unpaid orders don't count as usages. + if ( $order->needs_payment() ) { + continue; + } + + /* + * If the order has been refunded, treat coupon as unused. We'll consider the order to be + * refunded when there is a non-null refund amount, and the order total equals the refund amount. + * + * The use of == instead of === is deliberate, to account for differences in amount formatting. + */ + $refunded = $order->get_total_refunded(); + $total = $order->get_total(); + if ( $refunded && $total == $refunded ) { + continue; + } + + // If there was nothing discounted, then consider the coupon unused. + if ( ! $order->get_discount_total() ) { + continue; + } + + // Check for limited coupons, and add them to the count if the provide a discount. + $used_coupons = $order->get_items( 'coupon' ); + + /** @var WC_Order_Item_Coupon $used_coupon */ + foreach ( $used_coupons as $used_coupon ) { + if ( isset( $limited_coupons[ $used_coupon->get_code() ] ) && $used_coupon->get_discount() ) { + $limited_coupons[ $used_coupon->get_code() ]['count']++; + } + } + } + + // Check each coupon to see if it needs to be removed. + foreach ( $limited_coupons as $limited_coupon ) { + if ( self::get_coupon_limit( $limited_coupon['code'] ) <= $limited_coupon['count'] ) { + $subscription->remove_coupon( $limited_coupon['code'] ); + $subscription->add_order_note( sprintf( + /* translators: %1$s is the coupon code, %2$d is the number of payment usages */ + _n( + 'Limited use coupon "%1$s" removed from subscription. It has been used %2$d time.', + 'Limited use coupon "%1$s" removed from subscription. It has been used %2$d times.', + $limited_coupon['count'], + 'woocommerce-subscriptions' + ), + $limited_coupon['code'], + number_format_i18n( $limited_coupon['count'] ) + ) ); + } + } + } + + /** + * Add our limited coupon data to the Coupon list table. + * + * @since 4.0.0 + * + * @param string $column_name The name of the current column in the table. + * @param int $id The coupon ID. + */ + public static function add_limit_to_list_table( $column_name, $id ) { + if ( 'usage' !== $column_name ) { + return; + } + + $limit = self::get_coupon_limit( wc_get_coupon_code_by_id( $id ) ); + if ( false === $limit ) { + return; + } + + echo '
    '; + if ( $limit ) { + echo esc_html( sprintf( + /* translators: %d refers to the number of payments the coupon can be used for. */ + _n( 'Active for %d payment', 'Active for %d payments', $limit, 'woocommerce-subscriptions' ), + number_format_i18n( $limit ) + ) ); + } else { + esc_html_e( 'Active for unlimited payments', 'woocommerce-subscriptions' ); + } + } + + /** + * Determines if a given recurring cart contains a limited use coupon which when applied to a subscription will reach its usage limit within the subscription's length. + * + * @since 4.0.0 + * + * @param WC_Cart $recurring_cart The recurring cart object. + * @return bool + */ + public static function recurring_cart_contains_expiring_coupon( $recurring_cart ) { + $limited_recurring_coupons = array(); + + if ( isset( $recurring_cart->applied_coupons ) ) { + $limited_recurring_coupons = array_filter( $recurring_cart->applied_coupons, array( __CLASS__, 'coupon_is_limited' ) ); + } + + // Bail early if there are no limited coupons applied to the recurring cart or if there is no discount provided. + if ( empty( $limited_recurring_coupons ) || ! $recurring_cart->discount_cart ) { + return false; + } + + $has_expiring_coupon = false; + $subscription_length = wcs_cart_pluck( $recurring_cart, 'subscription_length' ); + $subscription_payments = $subscription_length / wcs_cart_pluck( $recurring_cart, 'subscription_period_interval' ); + + // Limited recurring coupons will always expire at some point on subscriptions with no length. + if ( empty( $subscription_length ) ) { + $has_expiring_coupon = true; + } else { + foreach ( $limited_recurring_coupons as $code ) { + if ( WC_Subscriptions_Coupon::get_coupon_limit( $code ) < $subscription_payments ) { + $has_expiring_coupon = true; + break; + } + } + } + + return $has_expiring_coupon; + } + + /** + * Filters the available gateways when there is a recurring coupon. + * + * @since 4.0.0 + * + * @param WC_Payment_Gateway[] $gateways The available payment gateways. + * @return WC_Payment_Gateway[] The filtered payment gateways. + */ + public static function gateways_subscription_amount_changes( $gateways ) { + + // If there are already no gateways or we're on the order-pay screen, bail early. + if ( empty( $gateways ) || is_wc_endpoint_url( 'order-pay' ) ) { + return $gateways; + } + + // See if this is a request to change payment for an existing subscription. + $change_payment = isset( $_GET['change_payment_method'] ) ? wc_clean( $_GET['change_payment_method'] ) : 0; + $has_limited_coupon = false; + + if ( $change_payment && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'] ) ) { + $subscription = wcs_get_subscription( $change_payment ); + $has_limited_coupon = self::order_has_limited_recurring_coupon( $subscription ); + } + + // If the cart doesn't have a limited coupon, and a change payment doesn't have a limited coupon, bail early. + if ( ! self::cart_contains_limited_recurring_coupon() && ! $has_limited_coupon ) { + return $gateways; + } + + // If we got this far, we should limit the gateways as needed. + $gateways = self::limit_gateways_subscription_amount_changes( $gateways ); + + // If there are no gateways now, it's because of the coupon. Filter the 'no available payment methods' message. + if ( empty( $gateways ) ) { + add_filter( 'woocommerce_no_available_payment_methods_message', array( __CLASS__, 'no_available_payment_methods_message' ), 20 ); + } + + return $gateways; + } + + /** + * Filter the message for when no payment gateways are available. + * + * @since 4.0.0 + * + * @param string $message The current message indicating there are no payment methods available.. + * @return string The filtered message indicating there are no payment methods available. + */ + public static function no_available_payment_methods_message() { + return __( 'Sorry, it seems there are no available payment methods which support the recurring coupon you are using. Please contact us if you require assistance or wish to make alternate arrangements.', 'woocommerce-subscriptions' ); + } + + /** + * Removes limited coupons from the recurring cart if the coupons limit is reached in the initial cart. + * + * @since 4.0.0 + * + * @param bool $bypass_default_checks Whether to bypass WC Subscriptions default conditions for removing a coupon. + * @param WC_Coupon $coupon The coupon to check. + * @param string $coupon_type The coupon's type. + * @param string $calculation_type The WC Subscriptions cart calculation mode. Can be 'recurring_total' or 'none'. @see WC_Subscriptions_Cart::get_calculation_type() + * + * @return bool Whether to bypass WC Subscriptions default conditions for removing a coupon. + */ + public static function maybe_remove_coupons_from_recurring_cart( $bypass_default_checks, $coupon, $coupon_type, $calculation_type, $cart ) { + + // Bypass this check if a third-party has already opted to bypass default conditions. + if ( $bypass_default_checks ) { + return $bypass_default_checks; + } + + if ( 'recurring_total' !== $calculation_type ) { + return $bypass_default_checks; + } + + if ( ! WC_Subscriptions_Coupon::is_recurring_coupon( $coupon_type ) ) { + return $bypass_default_checks; + } + + // Special handling for a single payment coupon. + if ( 1 === self::get_coupon_limit( $coupon->get_code() ) && 0 < WC()->cart->get_coupon_discount_amount( $coupon->get_code() ) ) { + $cart->remove_coupon( $coupon->get_code() ); + } + + return $bypass_default_checks; + } +} diff --git a/includes/class-wcs-manual-renewal-manager.php b/includes/class-wcs-manual-renewal-manager.php new file mode 100644 index 0000000..174b7fd --- /dev/null +++ b/includes/class-wcs-manual-renewal-manager.php @@ -0,0 +1,91 @@ + _x( 'Renewals', 'option section heading', 'woocommerce-subscriptions' ), + 'type' => 'title', + 'desc' => '', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_renewal_options', + ), + array( + 'name' => __( 'Manual Renewal Payments', 'woocommerce-subscriptions' ), + 'desc' => __( 'Accept Manual Renewals', 'woocommerce-subscriptions' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', + 'default' => 'no', + 'type' => 'checkbox', + // translators: placeholders are opening and closing link tags + 'desc_tip' => sprintf( __( 'With manual renewals, a customer\'s subscription is put on-hold until they login and pay to renew it. %1$sLearn more%2$s.', 'woocommerce-subscriptions' ), '', '' ), + 'checkboxgroup' => 'start', + 'show_if_checked' => 'option', + ), + + array( + 'desc' => __( 'Turn off Automatic Payments', 'woocommerce-subscriptions' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', + 'default' => 'no', + 'type' => 'checkbox', + // translators: placeholders are opening and closing link tags + 'desc_tip' => sprintf( __( 'If you don\'t want new subscription purchases to automatically charge renewal payments, you can turn off automatic payments. Existing automatic subscriptions will continue to charge customers automatically. %1$sLearn more%2$s.', 'woocommerce-subscriptions' ), '', '' ), + 'checkboxgroup' => 'end', + 'show_if_checked' => 'yes', + ), + + array( + 'type' => 'sectionend', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_renewal_options', + ), + ); + + if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_role_options', $manual_renewal_settings, 'multiple_settings', 'sectionend' ) ) { + $settings = array_merge( $settings, $manual_renewal_settings ); + } + + return $settings; + } + + /** + * Checks if manual renewals are required - automatic renewals are disabled. + * + * @since 4.0.0 + * @return bool Weather manual renewal is required. + */ + public static function is_manual_renewal_required() { + return 'yes' === get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ); + } + + /** + * Checks if manual renewals are enabled. + * + * @since 4.0.0 + * @return bool Weather manual renewal is enabled. + */ + public static function is_manual_renewal_enabled() { + return 'yes' === get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ); + } +} diff --git a/includes/class-wcs-staging.php b/includes/class-wcs-staging.php deleted file mode 100644 index 89c8626..0000000 --- a/includes/class-wcs-staging.php +++ /dev/null @@ -1,99 +0,0 @@ - tags - linked to staging site, 3: link to live site. - $message = sprintf( __( 'Payment processing skipped - renewal order created on %1$sstaging site%2$s under staging site lock. Live site is at %3$s', 'woocommerce-subscriptions' ), '', '', '' . $wcs_site_url . '' ); - - $renewal_order->add_order_note( $message ); - } - } - - /** - * Add a badge to the Subscriptions submenu when a site is operating under a staging site lock. - * - * @param array $subscription_order_type_data The WC_Subscription register order type data. - * @since 2.3.0 - */ - public static function maybe_add_menu_badge( $subscription_order_type_data ) { - - if ( isset( $subscription_order_type_data['labels']['menu_name'] ) && WC_Subscriptions::is_duplicate_site() ) { - $subscription_order_type_data['labels']['menu_name'] .= '' . esc_html__( 'staging', 'woocommerce-subscriptions' ) . ''; - } - - return $subscription_order_type_data; - } - - /** - * Handles admin requests to redisplay the staging site admin notice. - * - * @since 2.5.5 - */ - public static function maybe_reset_admin_notice() { - if ( isset( $_REQUEST['wcs_display_staging_notice'] ) && is_admin() && current_user_can( 'manage_options' ) ) { - delete_option( 'wcs_ignore_duplicate_siteurl_notice' ); - wp_safe_redirect( remove_query_arg( array( 'wcs_display_staging_notice' ) ) ); - } - } - - /** - * Displays a note under the edit subscription payment method field to explain why the subscription is set to Manual Renewal. - * - * @param WC_Subscription $subscription - * @since 2.6.0 - */ - public static function maybe_add_payment_method_note( $subscription ) { - if ( wcs_is_subscription( $subscription ) && WC_Subscriptions::is_duplicate_site() && $subscription->has_payment_gateway() && ! $subscription->get_requires_manual_renewal() ) { - printf( - '

    %s

    ', - esc_html__( 'Subscription locked to Manual Renewal while the store is in staging mode. Payment method changes will take effect in live mode.', 'woocommerce-subscriptions' ) - ); - } - } - - /** - * Returns the content for a tooltip explaining a subscription's payment method while in staging mode. - * - * @param WC_Subscription $subscription - * @return string HTML content for a tooltip. - * @since 2.6.0 - */ - public static function get_payment_method_tooltip( $subscription ) { - // translators: placeholder is a payment method title. - return '
    '; - } -} diff --git a/includes/class-wcs-subscriber-role-manager.php b/includes/class-wcs-subscriber-role-manager.php new file mode 100644 index 0000000..1f8c46c --- /dev/null +++ b/includes/class-wcs-subscriber-role-manager.php @@ -0,0 +1,98 @@ + $details ) { + $roles_options[ $role ] = translate_user_role( $details['name'] ); + } + + $role_settings = array( + array( + 'name' => __( 'Roles', 'woocommerce-subscriptions' ), + 'type' => 'title', + // translators: placeholders are tags + 'desc' => sprintf( __( 'Choose the default roles to assign to active and inactive subscribers. For record keeping purposes, a user account must be created for subscribers. Users with the %1$sadministrator%2$s role, such as yourself, will never be allocated these roles to prevent locking out administrators.', 'woocommerce-subscriptions' ), '', '' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_role_options', + ), + array( + 'name' => __( 'Subscriber Default Role', 'woocommerce-subscriptions' ), + 'desc' => __( 'When a subscription is activated, either manually or after a successful purchase, new users will be assigned this role.', 'woocommerce-subscriptions' ), + 'tip' => '', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_subscriber_role', + 'css' => 'min-width:150px;', + 'default' => 'subscriber', + 'type' => 'select', + 'options' => $roles_options, + 'desc_tip' => true, + ), + array( + 'name' => __( 'Inactive Subscriber Role', 'woocommerce-subscriptions' ), + 'desc' => __( 'If a subscriber\'s subscription is manually cancelled or expires, she will be assigned this role.', 'woocommerce-subscriptions' ), + 'tip' => '', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_cancelled_role', + 'css' => 'min-width:150px;', + 'default' => 'customer', + 'type' => 'select', + 'options' => $roles_options, + 'desc_tip' => true, + ), + array( + 'type' => 'sectionend', + 'id' => WC_Subscriptions_Admin::$option_prefix . '_role_options', + ), + ); + + WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_button_text', $role_settings, 'multiple_settings', 'sectionend' ); + return $settings; + } + + /** + * Gets the subscriber role. + * + * @since 4.0.0 + * + * @return string The role to apply to subscribers. + */ + public static function get_subscriber_role() { + return get_option( WC_Subscriptions_Admin::$option_prefix . '_subscriber_role', 'subscriber' ); + } + + /** + * Gets the inactive subscriber role. + * + * @since 4.0.0 + * + * @return string The role to apply to inactive subscribers. + */ + public static function get_inactive_subscriber_role() { + return get_option( WC_Subscriptions_Admin::$option_prefix . '_cancelled_role', 'customer' ); + } +} diff --git a/includes/class-wcs-template-loader.php b/includes/class-wcs-template-loader.php deleted file mode 100644 index 155e8d7..0000000 --- a/includes/class-wcs-template-loader.php +++ /dev/null @@ -1,117 +0,0 @@ -get_id() ) ) { - echo '
    ' . esc_html__( 'Invalid Subscription.', 'woocommerce-subscriptions' ) . ' ' . esc_html__( 'My Account', 'woocommerce-subscriptions' ) . '' . '
    '; - return; - } - - wc_get_template( 'myaccount/view-subscription.php', compact( 'subscription' ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); - } - - /** - * Get the subscription details template, which is part of the view subscription page. - * - * @param WC_Subscription $subscription Subscription object - * @since 2.2.19 - */ - public static function get_subscription_details_template( $subscription ) { - wc_get_template( 'myaccount/subscription-details.php', array( 'subscription' => $subscription ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); - } - - /** - * Get the subscription totals template, which is part of the view subscription page. - * - * @param WC_Subscription $subscription Subscription object - * @since 2.2.19 - */ - public static function get_subscription_totals_template( $subscription ) { - wc_get_template( 'myaccount/subscription-totals.php', array( 'subscription' => $subscription ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); - } - - /** - * Get the order downloads template, which is part of the view subscription page. - * - * @param WC_Subscription $subscription Subscription object - * @since 2.5.0 - */ - public static function get_order_downloads_template( $subscription ) { - if ( $subscription->has_downloadable_item() && $subscription->is_download_permitted() ) { - wc_get_template( - 'order/order-downloads.php', - array( - 'downloads' => $subscription->get_downloadable_items(), - 'show_title' => true, - ) - ); - } - } - - /** - * Gets the subscription totals table. - * - * @since 2.6.0 - * - * @param WC_Subscription $subscription The subscription to print the totals table for. - * @param bool $include_item_removal_links Whether the remove line item links should be included. - * @param array $totals The subscription totals rows to be displayed. - * @param bool $include_switch_links Whether the line item switch links should be included. - */ - public static function get_subscription_totals_table_template( $subscription, $include_item_removal_links, $totals, $include_switch_links = true ) { - - // If the switch links shouldn't be printed, remove the callback which prints them. - if ( false === $include_switch_links ) { - $callback_detached = remove_action( 'woocommerce_order_item_meta_end', 'WC_Subscriptions_Switcher::print_switch_link' ); - } - - wc_get_template( - 'myaccount/subscription-totals-table.php', - array( - 'subscription' => $subscription, - 'allow_item_removal' => $include_item_removal_links, - 'totals' => $totals, - ), - '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' - ); - - // Reattach the callback if it was successfully removed. - if ( false === $include_switch_links && $callback_detached ) { - add_action( 'woocommerce_order_item_meta_end', 'WC_Subscriptions_Switcher::print_switch_link', 10, 3 ); - } - } - - /** - * Gets the subscription receipt template content. - * - * @since 3.0.0 - * - * @param WC_Subscription $subscription The subscription to display the receipt for. - */ - public static function get_subscription_receipt_template( $subscription ) { - wc_get_template( 'checkout/subscription-receipt.php', array( 'subscription' => $subscription ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); - } -} diff --git a/includes/upgrades/class-wcs-upgrade-notice-manager.php b/includes/class-wcs-upgrade-notice-manager.php similarity index 74% rename from includes/upgrades/class-wcs-upgrade-notice-manager.php rename to includes/class-wcs-upgrade-notice-manager.php index e7ccce7..e008f83 100644 --- a/includes/upgrades/class-wcs-upgrade-notice-manager.php +++ b/includes/class-wcs-upgrade-notice-manager.php @@ -19,7 +19,7 @@ class WCS_Upgrade_Notice_Manager { * * @var string */ - protected static $version = '3.0.0'; + protected static $version = '3.1.0'; /** * The number of times the notice will be displayed before being dismissed automatically. @@ -77,34 +77,40 @@ class WCS_Upgrade_Notice_Manager { return; } - $version = _x( '3.0', 'plugin version number used in admin notice', 'woocommerce-subscriptions' ); + $version = _x( '3.1', 'plugin version number used in admin notice', 'woocommerce-subscriptions' ); $dismiss_url = wp_nonce_url( add_query_arg( 'dismiss_upgrade_notice', self::$version ), 'dismiss_upgrade_notice', '_wcsnonce' ); $notice = new WCS_Admin_Notice( 'notice notice-info', array(), $dismiss_url ); $features = array( array( - 'title' => __( 'Improved scheduled action data storage', 'woocommerce-subscriptions' ), - 'description' => __( 'Scheduled action data, which was previously stored in the WordPress post tables, has been moved to a custom database table. Amongst other benefits, this will greatly improve the performance of processing scheduled actions such as subscription payments.', 'woocommerce-subscriptions' ), + 'title' => __( 'v3 REST API endpoint support', 'woocommerce-subscriptions' ), + 'description' => sprintf( + // translators: 1-3: opening/closing tags - link to documentation. + __( 'Webhook and REST API users can now use v3 subscription endpoints. Click here to %1$slearn more%2$s about the REST API and check out the technical API docs %3$shere%2$s.', 'woocommerce-subscriptions' ), + '', + '', + '' + ), ), array( - 'title' => __( 'Increased processing rate for scheduled payments', 'woocommerce-subscriptions' ), + 'title' => __( 'WooCommerce checkout and cart blocks integration', 'woocommerce-subscriptions' ), 'description' => sprintf( // translators: 1-2: opening/closing tags - link to documentation. - __( 'Previous versions of Subscriptions relied on %1$sWP Cron%2$s to process subscription payments and other scheduled events. In 3.0, these events will now run on admin request with loopback support. This will significantly increase the throughput of payment processing.', 'woocommerce-subscriptions' ), - '', '' + __( 'Subscriptions is now compatible with the WooCommerce cart and checkout blocks. You can learn more about the compatibility status of the cart & checkout blocks %1$shere%2$s.', 'woocommerce-subscriptions' ), + '', '' ), ), ); - // translators: placeholder is Subscription version string ('2.3') + // translators: placeholder is Subscription version string ('3.1') $notice->set_heading( sprintf( __( 'Welcome to WooCommerce Subscriptions %s!', 'woocommerce-subscriptions' ), $version ) ); - $notice->set_content_template( 'update-welcome-notice.php', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'includes/upgrades/templates/', array( + $notice->set_content_template( 'update-welcome-notice.php', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory() . '/includes/upgrades/templates/', array( 'version' => $version, 'features' => $features, ) ); $notice->set_actions( array( array( 'name' => __( 'Learn more', 'woocommerce-subscriptions' ), - 'url' => 'https://docs.woocommerce.com/document/subscriptions/whats-new-in-subscriptions-3-0/', + 'url' => 'https://docs.woocommerce.com/document/subscriptions/whats-new-in-subscriptions-3-1/', ), ) ); diff --git a/includes/class-wcs-webhooks.php b/includes/class-wcs-webhooks.php index 5a09c18..97e11cc 100644 --- a/includes/class-wcs-webhooks.php +++ b/includes/class-wcs-webhooks.php @@ -107,10 +107,10 @@ class WCS_Webhooks { public static function add_topics_admin_menu( $topics ) { $front_end_topics = array( - 'subscription.created' => __( ' Subscription Created', 'woocommerce-subscriptions' ), - 'subscription.updated' => __( ' Subscription Updated', 'woocommerce-subscriptions' ), - 'subscription.deleted' => __( ' Subscription Deleted', 'woocommerce-subscriptions' ), - 'subscription.switched' => __( ' Subscription Switched', 'woocommerce-subscriptions' ), + 'subscription.created' => __( ' Subscription created', 'woocommerce-subscriptions' ), + 'subscription.updated' => __( ' Subscription updated', 'woocommerce-subscriptions' ), + 'subscription.deleted' => __( ' Subscription deleted', 'woocommerce-subscriptions' ), + 'subscription.switched' => __( ' Subscription switched', 'woocommerce-subscriptions' ), ); return array_merge( $topics, $front_end_topics ); @@ -125,27 +125,28 @@ class WCS_Webhooks { if ( 'subscription' == $resource && empty( $payload ) && wcs_is_subscription( $resource_id ) ) { $webhook = new WC_Webhook( $id ); - $event = $webhook->get_event(); $current_user = get_current_user_id(); wp_set_current_user( $webhook->get_user_id() ); - $webhook_api_version = ( method_exists( $webhook, 'get_api_version' ) ) ? $webhook->get_api_version() : 'legacy_v3'; - - switch ( $webhook_api_version ) { + switch ( $webhook->get_api_version() ) { case 'legacy_v3': WC()->api->WC_API_Subscriptions->register_routes( array() ); $payload = WC()->api->WC_API_Subscriptions->get_subscription( $resource_id ); break; case 'wp_api_v1': case 'wp_api_v2': - case 'wp_api_v3': + // There is no v2 subscritpion endpoint support so they fall back to v1. $request = new WP_REST_Request( 'GET' ); - $controller = new WC_REST_Subscriptions_Controller; + $controller = new WC_REST_Subscriptions_v1_Controller(); $request->set_param( 'id', $resource_id ); $result = $controller->get_item( $request ); $payload = isset( $result->data ) ? $result->data : array(); + + break; + case 'wp_api_v3': + $payload = wc()->api->get_endpoint_data( "/wc/v3/subscriptions/{$resource_id}" ); break; } diff --git a/includes/class-wcs-zero-initial-payment-checkout-manager.php b/includes/class-wcs-zero-initial-payment-checkout-manager.php new file mode 100644 index 0000000..87064e7 --- /dev/null +++ b/includes/class-wcs-zero-initial-payment-checkout-manager.php @@ -0,0 +1,85 @@ + __( '$0 Initial Checkout', 'woocommerce-subscriptions' ), + 'desc' => __( 'Allow $0 initial checkout without a payment method.', 'woocommerce-subscriptions' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_zero_initial_payment_requires_payment', + 'default' => 'no', + 'type' => 'checkbox', + 'desc_tip' => __( 'Allow a subscription product with a $0 initial payment to be purchased without providing a payment method. The customer will be required to provide a payment method at the end of the initial period to keep the subscription active.', 'woocommerce-subscriptions' ), + ); + + WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $setting ); + return $settings; + } + + /** + * Checks if a $0 checkout requires a payment method. + * + * @since 4.0.0 + * @return bool Whether a $0 initial checkout requires a payment method. + */ + public static function zero_initial_checkout_requires_payment() { + return 'yes' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_zero_initial_payment_requires_payment', 'no' ); + } + + /** + * Unhooks core Subscriptions functionality that requires payment on checkout for $0 subscription purchases, + * if the store has opted to bypass that via this feature. + * + * @since 4.0.0 + * + * @param bool $cart_needs_payment Whether the cart requires payment. + * @return bool + */ + public static function cart_needs_payment( $cart_needs_payment ) { + if ( ! self::zero_initial_checkout_requires_payment() ) { + remove_filter( 'woocommerce_cart_needs_payment', 'WC_Subscriptions_Cart::cart_needs_payment', 10, 2 ); + } + + return $cart_needs_payment; + } + + /** + * Unhooks core Subscriptions functionality that requires payment for a $0 subscription order, + * if the store has opted to bypass that via this feature. + * + * @since 4.0.0 + * + * @param bool $needs_payment + * @return bool + */ + public static function order_needs_payment( $needs_payment ) { + if ( ! self::zero_initial_checkout_requires_payment() ) { + remove_filter( 'woocommerce_order_needs_payment', 'WC_Subscriptions_Order::order_needs_payment', 10, 3 ); + } + + return $needs_payment; + } +} diff --git a/includes/early-renewal/class-wcs-cart-early-renewal.php b/includes/early-renewal/class-wcs-cart-early-renewal.php index 2fec4bc..50a40da 100644 --- a/includes/early-renewal/class-wcs-cart-early-renewal.php +++ b/includes/early-renewal/class-wcs-cart-early-renewal.php @@ -27,10 +27,19 @@ class WCS_Cart_Early_Renewal extends WCS_Cart_Renewal { add_action( 'woocommerce_checkout_create_order', array( $this, 'copy_subscription_meta_to_order' ), 90 ); // Record early renewal payments. - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { add_action( 'woocommerce_checkout_order_processed', array( $this, 'maybe_record_early_renewal' ), 100, 2 ); } else { add_action( 'woocommerce_checkout_create_order', array( $this, 'add_early_renewal_metadata_to_order' ), 100, 2 ); + if ( class_exists( 'Automattic\WooCommerce\Blocks\Package' ) ) { + if ( version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '7.2.0', '>=' ) ) { + add_action( 'woocommerce_store_api_checkout_update_order_meta', array( $this, 'add_early_renewal_metadata_to_order' ), 100, 1 ); + } elseif ( version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '6.3.0', '>=' ) ) { + add_action( 'woocommerce_blocks_checkout_update_order_meta', array( $this, 'add_early_renewal_metadata_to_order' ), 100, 1 ); + } else { + add_action( '__experimental_woocommerce_blocks_checkout_update_order_meta', array( $this, 'add_early_renewal_metadata_to_order' ), 100, 1 ); + } + } } // Process early renewal by making sure subscription's dates are updated. @@ -127,7 +136,7 @@ class WCS_Cart_Early_Renewal extends WCS_Cart_Renewal { * @since 2.3.0 */ public function maybe_record_early_renewal( $order_id, $posted_data ) { - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { wcs_deprecated_function( __METHOD__, '2.0', 'WCS_Cart_Early_Renewal::add_early_renewal_metadata_to_order( $order, $posted_data )' ); } @@ -178,7 +187,7 @@ class WCS_Cart_Early_Renewal extends WCS_Cart_Renewal { * @param array $data The data posted on checkout. * @since 2.3.0 */ - public function add_early_renewal_metadata_to_order( $order, $data ) { + public function add_early_renewal_metadata_to_order( $order, $data = array() ) { $cart_item = $this->cart_contains(); if ( ! $cart_item ) { diff --git a/includes/early-renewal/class-wcs-early-renewal-modal-handler.php b/includes/early-renewal/class-wcs-early-renewal-modal-handler.php index a918c33..d6c900b 100644 --- a/includes/early-renewal/class-wcs-early-renewal-modal-handler.php +++ b/includes/early-renewal/class-wcs-early-renewal-modal-handler.php @@ -45,6 +45,7 @@ class WCS_Early_Renewal_Modal_Handler { 'process_early_renewal' => true, 'wcs_nonce' => wp_create_nonce( 'wcs-renew-early-modal-' . $subscription->get_id() ), ) ), + 'data-payment-method' => $subscription->get_payment_method(), ), ); @@ -88,7 +89,7 @@ class WCS_Early_Renewal_Modal_Handler { 'new_next_payment_date' => $new_next_payment_date, ), '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . '/templates/' + WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/' ) ); } @@ -146,6 +147,9 @@ class WCS_Early_Renewal_Modal_Handler { wp_redirect( wcs_get_early_renewal_url( $subscription ) ); exit(); } else { + // Trigger the subscription payment complete hooks and reset suspension counts and user roles. + $subscription->payment_complete(); + wcs_update_dates_after_early_renewal( $subscription, $renewal_order ); wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-subscriptions' ), 'success' ); } diff --git a/includes/early-renewal/wcs-early-renewal-functions.php b/includes/early-renewal/wcs-early-renewal-functions.php index 9a5c3af..50e264c 100644 --- a/includes/early-renewal/wcs-early-renewal-functions.php +++ b/includes/early-renewal/wcs-early-renewal-functions.php @@ -95,32 +95,6 @@ function wcs_can_user_renew_early( $subscription, $user_id = 0 ) { return apply_filters( 'woocommerce_subscriptions_can_user_renew_early', $can_renew_early, $subscription, $user_id, $reason ); } -/** - * Check if a given order is a subscription renewal order. - * - * @param WC_Order|int $order The WC_Order object or ID of a WC_Order order. - * @since 2.3.0 - * @return bool True if the order contains an early renewal, otherwise false. - */ -function wcs_order_contains_early_renewal( $order ) { - - if ( ! is_object( $order ) ) { - $order = wc_get_order( $order ); - } - - $subscription_id = absint( wcs_get_objects_property( $order, 'subscription_renewal_early' ) ); - $is_early_renewal = wcs_is_order( $order ) && $subscription_id > 0; - - /** - * Allow third-parties to filter whether this order contains the early renewal flag. - * - * @since 2.3.0 - * @param bool $is_renewal True if early renewal meta was found on the order, otherwise false. - * @param WC_Order $order The WC_Order object. - */ - return apply_filters( 'woocommerce_subscriptions_is_early_renewal_order', $is_early_renewal, $order ); -} - /** * Returns a URL for early renewal of a subscription. * diff --git a/includes/gateways/class-wc-subscriptions-payment-gateways.php b/includes/gateways/class-wc-subscriptions-payment-gateways.php index 46bbdf1..b61c933 100644 --- a/includes/gateways/class-wc-subscriptions-payment-gateways.php +++ b/includes/gateways/class-wc-subscriptions-payment-gateways.php @@ -10,67 +10,27 @@ * @author Brent Shepherd * @since 1.0 */ -class WC_Subscriptions_Payment_Gateways { - - protected static $one_gateway_supports = array(); +class WC_Subscriptions_Payment_Gateways extends WC_Subscriptions_Core_Payment_Gateways { /** - * Bootstraps the class and hooks required actions & filters. + * Init WC_Subscriptions_Payment_Gateways actions & filters. * - * @since 1.0 + * @since 4.0.0 */ public static function init() { - - add_action( 'init', __CLASS__ . '::init_paypal', 5 ); // run before default priority 10 in case the site is using ALTERNATE_WP_CRON to avoid https://core.trac.wordpress.org/ticket/24160. - - add_filter( 'woocommerce_available_payment_gateways', __CLASS__ . '::get_available_payment_gateways' ); - - add_filter( 'woocommerce_no_available_payment_methods_message', __CLASS__ . '::no_available_payment_methods_message' ); - - add_filter( 'woocommerce_payment_gateways_renewal_support_status_html', __CLASS__ . '::payment_gateways_support_tooltip', 11, 2 ); - + parent::init(); // Trigger a hook for gateways to charge recurring payments. - add_action( 'woocommerce_scheduled_subscription_payment', __CLASS__ . '::gateway_scheduled_subscription_payment', 10, 1 ); + add_action( 'woocommerce_scheduled_subscription_payment', array( __CLASS__, 'gateway_scheduled_subscription_payment' ), 10, 1 ); - // Create a gateway specific hooks for subscription events. - add_action( 'woocommerce_subscription_status_updated', __CLASS__ . '::trigger_gateway_status_updated_hook', 10, 2 ); + add_filter( 'woocommerce_subscriptions_admin_recurring_payment_information', array( __CLASS__, 'add_recurring_payment_gateway_information' ), 10, 2 ); } /** - * Instantiate our custom PayPal class - * - * @since 2.0 - */ - public static function init_paypal() { - WCS_PayPal::init(); - } - - /** - * Returns a payment gateway object by gateway's ID, or false if it could not find the gateway. - * - * @since 1.2.4 - */ - public static function get_payment_gateway( $gateway_id ) { - $found_gateway = false; - - if ( WC()->payment_gateways ) { - foreach ( WC()->payment_gateways->payment_gateways() as $gateway ) { - if ( $gateway_id == $gateway->id ) { - $found_gateway = $gateway; - } - } - } - - return $found_gateway; - } - - /** - * Only display the gateways which support subscriptions if manual payments are not allowed. + * Display the gateways which support subscriptions if manual payments are not allowed. * * @since 1.0 */ public static function get_available_payment_gateways( $available_gateways ) { - // We don't want to filter the available payment methods while the customer is paying for a standard order via the order-pay screen. if ( is_wc_endpoint_url( 'order-pay' ) ) { return $available_gateways; @@ -80,7 +40,7 @@ class WC_Subscriptions_Payment_Gateways { return $available_gateways; } - $accept_manual_renewals = ( 'no' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ) ); + $accept_manual_renewals = wcs_is_manual_renewal_enabled(); $subscriptions_in_cart = is_array( WC()->cart->recurring_carts ) ? count( WC()->cart->recurring_carts ) : 0; foreach ( $available_gateways as $gateway_id => $gateway ) { @@ -101,79 +61,25 @@ class WC_Subscriptions_Payment_Gateways { } /** - * Helper function to check if at least one payment gateway on the site supports a certain subscription feature. + * Fire a gateway specific hook for when a subscription payment is due. * - * @since 2.0 + * @since 1.0 */ - public static function one_gateway_supports( $supports_flag ) { - - // Only check if we haven't already run the check - if ( ! isset( self::$one_gateway_supports[ $supports_flag ] ) ) { - - self::$one_gateway_supports[ $supports_flag ] = false; - - foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway ) { - if ( $gateway->supports( $supports_flag ) ) { - self::$one_gateway_supports[ $supports_flag ] = true; - break; - } - } + public static function gateway_scheduled_subscription_payment( $subscription_id, $deprecated = null ) { + if ( ! is_object( $subscription_id ) ) { + $subscription = wcs_get_subscription( $subscription_id ); + } else { + $subscription = $subscription_id; } - return self::$one_gateway_supports[ $supports_flag ]; - } - - /** - * Improve message displayed on checkout when a subscription is in the cart but not gateways support subscriptions. - * - * @since 1.5.2 - */ - public static function no_available_payment_methods_message( $no_gateways_message ) { - if ( WC_Subscriptions_Cart::cart_contains_subscription() && 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ) ) { - if ( current_user_can( 'manage_woocommerce' ) ) { - // translators: 1-2: opening/closing tags - link to documentation. - $no_gateways_message = sprintf( __( 'Sorry, it seems there are no available payment methods which support subscriptions. Please see %1$sEnabling Payment Gateways for Subscriptions%2$s if you require assistance.', 'woocommerce-subscriptions' ), '', '' ); - } else { - $no_gateways_message = __( 'Sorry, it seems there are no available payment methods which support subscriptions. Please contact us if you require assistance or wish to make alternate arrangements.', 'woocommerce-subscriptions' ); - } + if ( false === $subscription ) { + // translators: %d: subscription ID. + throw new InvalidArgumentException( sprintf( __( 'Subscription doesn\'t exist in scheduled action: %d', 'woocommerce-subscriptions' ), $subscription_id ) ); } - return $no_gateways_message; - } - - /** - * Fire a gateway specific whenever a subscription's status is changed. - * - * @since 2.0 - */ - public static function trigger_gateway_status_updated_hook( $subscription, $new_status ) { - - if ( $subscription->is_manual() ) { - return; + if ( ! $subscription->is_manual() && ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) ) { + self::trigger_gateway_renewal_payment_hook( $subscription->get_last_order( 'all', 'renewal' ) ); } - - switch ( $new_status ) { - case 'active': - $hook_prefix = 'woocommerce_subscription_activated_'; - break; - case 'on-hold': - $hook_prefix = 'woocommerce_subscription_on-hold_'; - break; - case 'pending-cancel': - $hook_prefix = 'woocommerce_subscription_pending-cancel_'; - break; - case 'cancelled': - $hook_prefix = 'woocommerce_subscription_cancelled_'; - break; - case 'expired': - $hook_prefix = 'woocommerce_subscription_expired_'; - break; - default: - $hook_prefix = apply_filters( 'woocommerce_subscriptions_gateway_status_updated_hook_prefix', 'woocommerce_subscription_status_updated_', $subscription, $new_status ); - break; - } - - do_action( $hook_prefix . $subscription->get_payment_method(), $subscription ); } /** @@ -193,147 +99,37 @@ class WC_Subscriptions_Payment_Gateways { } /** - * Fire a gateway specific hook for when a subscription payment is due. + * Returns whether the subscription payment gateway has an available gateway. * - * @since 1.0 + * @since 4.0.0 + * @param WC_Subscription $subscription Subscription to check if the gateway is available. + * @return bool */ - public static function gateway_scheduled_subscription_payment( $subscription_id, $deprecated = null ) { - - // Passing the old $user_id/$subscription_key parameters - if ( null != $deprecated ) { - _deprecated_argument( __METHOD__, '2.0', 'Second parameter is deprecated' ); - $subscription = wcs_get_subscription_from_key( $deprecated ); - } elseif ( ! is_object( $subscription_id ) ) { - $subscription = wcs_get_subscription( $subscription_id ); - } else { - // Support receiving a full subscription object for unit testing - $subscription = $subscription_id; - } - - if ( false === $subscription ) { - // translators: %d: subscription ID. - throw new InvalidArgumentException( sprintf( __( 'Subscription doesn\'t exist in scheduled action: %d', 'woocommerce-subscriptions' ), $subscription_id ) ); - } - - if ( ! $subscription->is_manual() && ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) ) { - self::trigger_gateway_renewal_payment_hook( $subscription->get_last_order( 'all', 'renewal' ) ); - } + public static function has_available_payment_method( $subscription ) { + return wc_get_payment_gateway_by_order( $subscription ) ? true : false; } /** - * Display a list of each gateway supported features in a tooltip + * Returns whether the gateway supports subscriptions and automatic renewals. * - * @since 2.5.0 + * @since 4.0.0 + * @param WC_Gateway $gateway Gateway to check if it supports subscriptions. + * @return bool */ - public static function payment_gateways_support_tooltip( $status_html, $gateway ) { - - if ( ( ! is_array( $gateway->supports ) || ! in_array( 'subscriptions', $gateway->supports ) ) && 'paypal' !== $gateway->id ) { - return $status_html; - } - - $core_features = (array) apply_filters( 'woocommerce_subscriptions_payment_gateway_features_list', $gateway->supports, $gateway ); - $subscription_features = $change_payment_method_features = array(); - - foreach ( $core_features as $key => $feature ) { - - // Skip any non-subscription related features. - if ( 'gateway_scheduled_payments' !== $feature && false === strpos( $feature, 'subscription' ) ) { - continue; - } - - $feature = str_replace( 'subscription_', '', $feature ); - - if ( 0 === strpos( $feature, 'payment_method' ) ) { - switch ( $feature ) { - case 'payment_method_change': - $change_payment_method_features[] = 'payment method change'; - break; - - case 'payment_method_change_customer': - $change_payment_method_features[] = 'customer change payment'; - break; - - case 'payment_method_change_admin': - $change_payment_method_features[] = 'admin change payment'; - break; - - default: - $change_payment_method_features[] = str_replace( 'payment_method', ' ', $feature ); - break; - } - } else { - $subscription_features[] = $feature; - } - - unset( $core_features[ $key ] ); - } - - $status_html .= ''; - - $allowed_html = wp_kses_allowed_html( 'post' ); - $allowed_html['span']['data-tip'] = true; - - return wp_kses( $status_html, $allowed_html ); + public static function gateway_supports_subscriptions( $gateway ) { + return ( is_array( $gateway->supports ) && in_array( 'subscriptions', $gateway->supports, true ) ) || 'paypal' === $gateway->id; } /** - * Fire a gateway specific hook for when a subscription is activated. - * - * @since 1.0 + * Add links to find additional payment gateways to information after the Settings->Payments->Payment Methods table. */ - public static function trigger_gateway_activated_subscription_hook( $user_id, $subscription_key ) { - _deprecated_function( __METHOD__, '2.0', __CLASS__ . '::trigger_gateway_status_updated_hook()' ); - self::trigger_gateway_status_updated_hook( wcs_get_subscription_from_key( $subscription_key ), 'active' ); - } - - /** - * Fire a gateway specific hook for when a subscription is activated. - * - * @since 1.0 - */ - public static function trigger_gateway_reactivated_subscription_hook( $user_id, $subscription_key ) { - _deprecated_function( __METHOD__, '2.0', __CLASS__ . '::trigger_gateway_status_updated_hook()' ); - self::trigger_gateway_status_updated_hook( wcs_get_subscription_from_key( $subscription_key ), 'active' ); - } - - /** - * Fire a gateway specific hook for when a subscription is on-hold. - * - * @since 1.2 - */ - public static function trigger_gateway_subscription_put_on_hold_hook( $user_id, $subscription_key ) { - _deprecated_function( __METHOD__, '2.0', __CLASS__ . '::trigger_gateway_status_updated_hook()' ); - self::trigger_gateway_status_updated_hook( wcs_get_subscription_from_key( $subscription_key ), 'on-hold' ); - } - - /** - * Fire a gateway specific when a subscription is cancelled. - * - * @since 1.0 - */ - public static function trigger_gateway_cancelled_subscription_hook( $user_id, $subscription_key ) { - _deprecated_function( __METHOD__, '2.0', __CLASS__ . '::trigger_gateway_status_updated_hook()' ); - self::trigger_gateway_status_updated_hook( wcs_get_subscription_from_key( $subscription_key ), 'cancelled' ); - } - - /** - * Fire a gateway specific hook when a subscription expires. - * - * @since 1.0 - */ - public static function trigger_gateway_subscription_expired_hook( $user_id, $subscription_key ) { - _deprecated_function( __METHOD__, '2.0', __CLASS__ . '::trigger_gateway_status_updated_hook()' ); - self::trigger_gateway_status_updated_hook( wcs_get_subscription_from_key( $subscription_key ), 'expired' ); + public static function add_recurring_payment_gateway_information( $settings, $option_prefix ) { + $settings[] = array( + // translators: $1-$2: opening and closing tags. Link to documents->payment gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions shop page + 'desc' => sprintf( __( 'Find new gateways that %1$ssupport automatic subscription payments%2$s in the official %3$sWooCommerce Marketplace%4$s.', 'woocommerce-subscriptions' ), '', '', '', '' ), + 'id' => $option_prefix . '_payment_gateways_additional', + 'type' => 'informational', + ); + return $settings; } } diff --git a/includes/libraries/action-scheduler/action-scheduler.php b/includes/libraries/action-scheduler/action-scheduler.php deleted file mode 100644 index 4ffb266..0000000 --- a/includes/libraries/action-scheduler/action-scheduler.php +++ /dev/null @@ -1,53 +0,0 @@ -. - * - */ - -if ( ! function_exists( 'action_scheduler_register_3_dot_0_dot_1' ) ) { - - if ( ! class_exists( 'ActionScheduler_Versions' ) ) { - require_once( 'classes/ActionScheduler_Versions.php' ); - add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 ); - } - - add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_0_dot_1', 0, 0 ); - - function action_scheduler_register_3_dot_0_dot_1() { - $versions = ActionScheduler_Versions::instance(); - $versions->register( '3.0.1', 'action_scheduler_initialize_3_dot_0_dot_1' ); - } - - function action_scheduler_initialize_3_dot_0_dot_1() { - require_once( 'classes/abstracts/ActionScheduler.php' ); - ActionScheduler::init( __FILE__ ); - } - - // Support usage in themes - load this version if no plugin has loaded a version yet. - if ( did_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) { - action_scheduler_register_3_dot_0_dot_1(); - do_action( 'action_scheduler_pre_theme_init' ); - ActionScheduler_Versions::initialize_latest_version(); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_ActionClaim.php b/includes/libraries/action-scheduler/classes/ActionScheduler_ActionClaim.php deleted file mode 100644 index 8b56816..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_ActionClaim.php +++ /dev/null @@ -1,23 +0,0 @@ -id = $id; - $this->action_ids = $action_ids; - } - - public function get_id() { - return $this->id; - } - - public function get_actions() { - return $this->action_ids; - } -} - \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_ActionFactory.php b/includes/libraries/action-scheduler/classes/ActionScheduler_ActionFactory.php deleted file mode 100644 index 890e8a6..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_ActionFactory.php +++ /dev/null @@ -1,179 +0,0 @@ -get_date() ); - } - break; - default : - $action_class = 'ActionScheduler_FinishedAction'; - break; - } - - $action_class = apply_filters( 'action_scheduler_stored_action_class', $action_class, $status, $hook, $args, $schedule, $group ); - - $action = new $action_class( $hook, $args, $schedule, $group ); - - /** - * Allow 3rd party code to change the instantiated action for a given hook, args, schedule and group. - * - * @param ActionScheduler_Action $action The instantiated action. - * @param string $hook The instantiated action's hook. - * @param array $args The instantiated action's args. - * @param ActionScheduler_Schedule $schedule The instantiated action's schedule. - * @param string $group The instantiated action's group. - */ - return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group ); - } - - /** - * Enqueue an action to run one time, as soon as possible (rather a specific scheduled time). - * - * This method creates a new action with the NULLSchedule. This schedule maps to a MySQL datetime string of - * 0000-00-00 00:00:00. This is done to create a psuedo "async action" type that is fully backward compatible. - * Existing queries to claim actions claim by date, meaning actions scheduled for 0000-00-00 00:00:00 will - * always be claimed prior to actions scheduled for a specific date. This makes sure that any async action is - * given priority in queue processing. This has the added advantage of making sure async actions can be - * claimed by both the existing WP Cron and WP CLI runners, as well as a new async request runner. - * - * @param string $hook The hook to trigger when this action runs - * @param array $args Args to pass when the hook is triggered - * @param string $group A group to put the action in - * - * @return string The ID of the stored action - */ - public function async( $hook, $args = array(), $group = '' ) { - $schedule = new ActionScheduler_NullSchedule(); - $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); - return $this->store( $action ); - } - - /** - * @param string $hook The hook to trigger when this action runs - * @param array $args Args to pass when the hook is triggered - * @param int $when Unix timestamp when the action will run - * @param string $group A group to put the action in - * - * @return string The ID of the stored action - */ - public function single( $hook, $args = array(), $when = null, $group = '' ) { - $date = as_get_datetime_object( $when ); - $schedule = new ActionScheduler_SimpleSchedule( $date ); - $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); - return $this->store( $action ); - } - - /** - * Create the first instance of an action recurring on a given interval. - * - * @param string $hook The hook to trigger when this action runs - * @param array $args Args to pass when the hook is triggered - * @param int $first Unix timestamp for the first run - * @param int $interval Seconds between runs - * @param string $group A group to put the action in - * - * @return string The ID of the stored action - */ - public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) { - if ( empty($interval) ) { - return $this->single( $hook, $args, $first, $group ); - } - $date = as_get_datetime_object( $first ); - $schedule = new ActionScheduler_IntervalSchedule( $date, $interval ); - $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); - return $this->store( $action ); - } - - /** - * Create the first instance of an action recurring on a Cron schedule. - * - * @param string $hook The hook to trigger when this action runs - * @param array $args Args to pass when the hook is triggered - * @param int $base_timestamp The first instance of the action will be scheduled - * to run at a time calculated after this timestamp matching the cron - * expression. This can be used to delay the first instance of the action. - * @param int $schedule A cron definition string - * @param string $group A group to put the action in - * - * @return string The ID of the stored action - */ - public function cron( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '' ) { - if ( empty($schedule) ) { - return $this->single( $hook, $args, $base_timestamp, $group ); - } - $date = as_get_datetime_object( $base_timestamp ); - $cron = CronExpression::factory( $schedule ); - $schedule = new ActionScheduler_CronSchedule( $date, $cron ); - $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); - return $this->store( $action ); - } - - /** - * Create a successive instance of a recurring or cron action. - * - * Importantly, the action will be rescheduled to run based on the current date/time. - * That means when the action is scheduled to run in the past, the next scheduled date - * will be pushed forward. For example, if a recurring action set to run every hour - * was scheduled to run 5 seconds ago, it will be next scheduled for 1 hour in the - * future, which is 1 hour and 5 seconds from when it was last scheduled to run. - * - * Alternatively, if the action is scheduled to run in the future, and is run early, - * likely via manual intervention, then its schedule will change based on the time now. - * For example, if a recurring action set to run every day, and is run 12 hours early, - * it will run again in 24 hours, not 36 hours. - * - * This slippage is less of an issue with Cron actions, as the specific run time can - * be set for them to run, e.g. 1am each day. In those cases, and entire period would - * need to be missed before there was any change is scheduled, e.g. in the case of an - * action scheduled for 1am each day, the action would need to run an entire day late. - * - * @param ActionScheduler_Action $action The existing action. - * - * @return string The ID of the stored action - * @throws InvalidArgumentException If $action is not a recurring action. - */ - public function repeat( $action ) { - $schedule = $action->get_schedule(); - $next = $schedule->get_next( as_get_datetime_object() ); - - if ( is_null( $next ) || ! $schedule->is_recurring() ) { - throw new InvalidArgumentException( __( 'Invalid action - must be a recurring action.', 'action-scheduler' ) ); - } - - $schedule_class = get_class( $schedule ); - $new_schedule = new $schedule( $next, $schedule->get_recurrence(), $schedule->get_first_date() ); - $new_action = new ActionScheduler_Action( $action->get_hook(), $action->get_args(), $new_schedule, $action->get_group() ); - return $this->store( $new_action ); - } - - /** - * @param ActionScheduler_Action $action - * - * @return string The ID of the stored action - */ - protected function store( ActionScheduler_Action $action ) { - $store = ActionScheduler_Store::instance(); - return $store->save_action( $action ); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php b/includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php deleted file mode 100644 index b46ddc2..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php +++ /dev/null @@ -1,137 +0,0 @@ -render(); - } - - /** - * Registers action-scheduler into WooCommerce > System status. - * - * @param array $tabs An associative array of tab key => label. - * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs - */ - public function register_system_status_tab( array $tabs ) { - $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' ); - - return $tabs; - } - - /** - * Include Action Scheduler's administration under the Tools menu. - * - * A menu under the Tools menu is important for backward compatibility (as that's - * where it started), and also provides more convenient access than the WooCommerce - * System Status page, and for sites where WooCommerce isn't active. - */ - public function register_menu() { - $hook_suffix = add_submenu_page( - 'tools.php', - __( 'Scheduled Actions', 'action-scheduler' ), - __( 'Scheduled Actions', 'action-scheduler' ), - 'manage_options', - 'action-scheduler', - array( $this, 'render_admin_ui' ) - ); - add_action( 'load-' . $hook_suffix , array( $this, 'process_admin_ui' ) ); - } - - /** - * Triggers processing of any pending actions. - */ - public function process_admin_ui() { - $table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() ); - $table->process_actions(); - } - - /** - * Renders the Admin UI - */ - public function render_admin_ui() { - $table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() ); - $table->display_page(); - } - - /** - * Provide more information about the screen and its data in the help tab. - */ - public function add_help_tabs() { - $screen = get_current_screen(); - - if ( ! $screen || self::$screen_id != $screen->id ) { - return; - } - - $screen->add_help_tab( - array( - 'id' => 'action_scheduler_about', - 'title' => __( 'About', 'action-scheduler' ), - 'content' => - '

    ' . __( 'About Action Scheduler', 'action-scheduler' ) . '

    ' . - '

    ' . - __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) . - '

    ', - ) - ); - - $screen->add_help_tab( - array( - 'id' => 'action_scheduler_columns', - 'title' => __( 'Columns', 'action-scheduler' ), - 'content' => - '

    ' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '

    ' . - '
      ' . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) . - sprintf( '
    • %1$s: %2$s
    • ', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) . - '
    ', - ) - ); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php b/includes/libraries/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php deleted file mode 100644 index c1ab036..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php +++ /dev/null @@ -1,96 +0,0 @@ -store = $store; - } - - /** - * Handle async requests - * - * Run a queue, and maybe dispatch another async request to run another queue - * if there are still pending actions after completing a queue in this request. - */ - protected function handle() { - do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context - - $sleep_seconds = $this->get_sleep_seconds(); - - if ( $sleep_seconds ) { - sleep( $sleep_seconds ); - } - - $this->maybe_dispatch(); - } - - /** - * If the async request runner is needed and allowed to run, dispatch a request. - */ - public function maybe_dispatch() { - if ( ! $this->allow() ) { - return; - } - - $this->dispatch(); - } - - /** - * Only allow async requests when needed. - * - * Also allow 3rd party code to disable running actions via async requests. - */ - protected function allow() { - - if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) { - $allow = false; - } else { - $allow = true; - } - - return apply_filters( 'action_scheduler_allow_async_request_runner', $allow ); - } - - /** - * Chaining async requests can crash MySQL. A brief sleep call in PHP prevents that. - */ - protected function get_sleep_seconds() { - return apply_filters( 'action_scheduler_async_request_sleep_seconds', 1, $this ); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_Compatibility.php b/includes/libraries/action-scheduler/classes/ActionScheduler_Compatibility.php deleted file mode 100644 index c06e5a4..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_Compatibility.php +++ /dev/null @@ -1,99 +0,0 @@ - $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) { - if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) { - return $filtered_limit; - } else { - return false; - } - } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) { - if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) { - return $wp_max_limit; - } else { - return false; - } - } - return false; - } - - /** - * Attempts to raise the PHP timeout for time intensive processes. - * - * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available. - * - * @param int The time limit in seconds. - */ - public static function raise_time_limit( $limit = 0 ) { - if ( $limit < ini_get( 'max_execution_time' ) ) { - return; - } - - if ( function_exists( 'wc_set_time_limit' ) ) { - wc_set_time_limit( $limit ); - } elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { - @set_time_limit( $limit ); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_DataController.php b/includes/libraries/action-scheduler/classes/ActionScheduler_DataController.php deleted file mode 100644 index d2c889b..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_DataController.php +++ /dev/null @@ -1,177 +0,0 @@ -=' ); - return $php_support && apply_filters( 'action_scheduler_migration_dependencies_met', true ); - } - - /** - * Get a flag indicating whether the migration is complete. - * - * @return bool Whether the flag has been set marking the migration as complete - */ - public static function is_migration_complete() { - return get_option( self::STATUS_FLAG ) === self::STATUS_COMPLETE; - } - - /** - * Mark the migration as complete. - */ - public static function mark_migration_complete() { - update_option( self::STATUS_FLAG, self::STATUS_COMPLETE ); - } - - /** - * Set the action store class name. - * - * @param string $class Classname of the store class. - * - * @return string - */ - public static function set_store_class( $class ) { - return self::DATASTORE_CLASS; - } - - /** - * Set the action logger class name. - * - * @param string $class Classname of the logger class. - * - * @return string - */ - public static function set_logger_class( $class ) { - return self::LOGGER_CLASS; - } - - /** - * Set the sleep time in seconds. - * - * @param integer $sleep_time The number of seconds to pause before resuming operation. - */ - public static function set_sleep_time( $sleep_time ) { - self::$sleep_time = $sleep_time; - } - - /** - * Set the tick count required for freeing memory. - * - * @param integer $free_ticks The number of ticks to free memory on. - */ - public static function set_free_ticks( $free_ticks ) { - self::$free_ticks = $free_ticks; - } - - /** - * Free memory if conditions are met. - * - * @param int $ticks Current tick count. - */ - public static function maybe_free_memory( $ticks ) { - if ( self::$free_ticks && 0 === $ticks % self::$free_ticks ) { - self::free_memory(); - } - } - - /** - * Reduce memory footprint by clearing the database query and object caches. - */ - public static function free_memory() { - if ( 0 < self::$sleep_time ) { - /* translators: %d: amount of time */ - \WP_CLI::warning( sprintf( _n( 'Stopped the insanity for %d second', 'Stopped the insanity for %d seconds', self::$sleep_time, 'action-scheduler' ), self::$sleep_time ) ); - sleep( self::$sleep_time ); - } - - \WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) ); - - /** - * @var $wpdb \wpdb - * @var $wp_object_cache \WP_Object_Cache - */ - global $wpdb, $wp_object_cache; - - $wpdb->queries = array(); - - if ( ! is_a( $wp_object_cache, 'WP_Object_Cache' ) ) { - return; - } - - $wp_object_cache->group_ops = array(); - $wp_object_cache->stats = array(); - $wp_object_cache->memcache_debug = array(); - $wp_object_cache->cache = array(); - - if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) { - call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important - } - } - - /** - * Connect to table datastores if migration is complete. - * Otherwise, proceed with the migration if the dependencies have been met. - */ - public static function init() { - if ( self::is_migration_complete() ) { - add_filter( 'action_scheduler_store_class', array( 'ActionScheduler_DataController', 'set_store_class' ), 100 ); - add_filter( 'action_scheduler_logger_class', array( 'ActionScheduler_DataController', 'set_logger_class' ), 100 ); - } elseif ( self::dependencies_met() ) { - Controller::init(); - } - - add_action( 'action_scheduler/progress_tick', array( 'ActionScheduler_DataController', 'maybe_free_memory' ) ); - } - - /** - * Singleton factory. - */ - public static function instance() { - if ( ! isset( self::$instance ) ) { - self::$instance = new static(); - } - - return self::$instance; - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_DateTime.php b/includes/libraries/action-scheduler/classes/ActionScheduler_DateTime.php deleted file mode 100644 index 5e8743c..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_DateTime.php +++ /dev/null @@ -1,76 +0,0 @@ -format( 'U' ); - } - - /** - * Set the UTC offset. - * - * This represents a fixed offset instead of a timezone setting. - * - * @param $offset - */ - public function setUtcOffset( $offset ) { - $this->utcOffset = intval( $offset ); - } - - /** - * Returns the timezone offset. - * - * @return int - * @link http://php.net/manual/en/datetime.getoffset.php - */ - public function getOffset() { - return $this->utcOffset ? $this->utcOffset : parent::getOffset(); - } - - /** - * Set the TimeZone associated with the DateTime - * - * @param DateTimeZone $timezone - * - * @return static - * @link http://php.net/manual/en/datetime.settimezone.php - */ - public function setTimezone( $timezone ) { - $this->utcOffset = 0; - parent::setTimezone( $timezone ); - - return $this; - } - - /** - * Get the timestamp with the WordPress timezone offset added or subtracted. - * - * @since 3.0.0 - * @return int - */ - public function getOffsetTimestamp() { - return $this->getTimestamp() + $this->getOffset(); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_Exception.php b/includes/libraries/action-scheduler/classes/ActionScheduler_Exception.php deleted file mode 100644 index 353d3c0..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_Exception.php +++ /dev/null @@ -1,11 +0,0 @@ -store = $store; - } - - public function attach( ActionScheduler_ActionClaim $claim ) { - $this->claim = $claim; - add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) ); - add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 ); - add_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0, 0 ); - add_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0, 0 ); - add_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0, 0 ); - } - - public function detach() { - $this->claim = NULL; - $this->untrack_action(); - remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) ); - remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 ); - remove_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0 ); - remove_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0 ); - remove_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0 ); - } - - public function track_current_action( $action_id ) { - $this->action_id = $action_id; - } - - public function untrack_action() { - $this->action_id = 0; - } - - public function handle_unexpected_shutdown() { - if ( $error = error_get_last() ) { - if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) { - if ( !empty($this->action_id) ) { - $this->store->mark_failure( $this->action_id ); - do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error ); - } - } - $this->store->release_claim( $this->claim ); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_InvalidActionException.php b/includes/libraries/action-scheduler/classes/ActionScheduler_InvalidActionException.php deleted file mode 100644 index 40b4559..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_InvalidActionException.php +++ /dev/null @@ -1,47 +0,0 @@ - label). - * - * @var array - */ - protected $columns = array(); - - /** - * Actions (name => label). - * - * @var array - */ - protected $row_actions = array(); - - /** - * The active data stores - * - * @var ActionScheduler_Store - */ - protected $store; - - /** - * A logger to use for getting action logs to display - * - * @var ActionScheduler_Logger - */ - protected $logger; - - /** - * A ActionScheduler_QueueRunner runner instance (or child class) - * - * @var ActionScheduler_QueueRunner - */ - protected $runner; - - /** - * Bulk actions. The key of the array is the method name of the implementation: - * - * bulk_(array $ids, string $sql_in). - * - * See the comments in the parent class for further details - * - * @var array - */ - protected $bulk_actions = array(); - - /** - * Flag variable to render our notifications, if any, once. - * - * @var bool - */ - protected static $did_notification = false; - - /** - * Array of seconds for common time periods, like week or month, alongside an internationalised string representation, i.e. "Day" or "Days" - * - * @var array - */ - private static $time_periods; - - /** - * Sets the current data store object into `store->action` and initialises the object. - * - * @param ActionScheduler_Store $store - * @param ActionScheduler_Logger $logger - * @param ActionScheduler_QueueRunner $runner - */ - public function __construct( ActionScheduler_Store $store, ActionScheduler_Logger $logger, ActionScheduler_QueueRunner $runner ) { - - $this->store = $store; - $this->logger = $logger; - $this->runner = $runner; - - $this->table_header = __( 'Scheduled Actions', 'action-scheduler' ); - - $this->bulk_actions = array( - 'delete' => __( 'Delete', 'action-scheduler' ), - ); - - $this->columns = array( - 'hook' => __( 'Hook', 'action-scheduler' ), - 'status' => __( 'Status', 'action-scheduler' ), - 'args' => __( 'Arguments', 'action-scheduler' ), - 'group' => __( 'Group', 'action-scheduler' ), - 'recurrence' => __( 'Recurrence', 'action-scheduler' ), - 'schedule' => __( 'Scheduled Date', 'action-scheduler' ), - 'log_entries' => __( 'Log', 'action-scheduler' ), - ); - - $this->sort_by = array( - 'schedule', - 'hook', - 'group', - ); - - $this->search_by = array( - 'hook', - 'args', - 'claim_id', - ); - - $request_status = $this->get_request_status(); - - if ( empty( $request_status ) ) { - $this->sort_by[] = 'status'; - } elseif ( in_array( $request_status, array( 'in-progress', 'failed' ) ) ) { - $this->columns += array( 'claim_id' => __( 'Claim ID', 'action-scheduler' ) ); - $this->sort_by[] = 'claim_id'; - } - - $this->row_actions = array( - 'hook' => array( - 'run' => array( - 'name' => __( 'Run', 'action-scheduler' ), - 'desc' => __( 'Process the action now as if it were run as part of a queue', 'action-scheduler' ), - ), - 'cancel' => array( - 'name' => __( 'Cancel', 'action-scheduler' ), - 'desc' => __( 'Cancel the action now to avoid it being run in future', 'action-scheduler' ), - 'class' => 'cancel trash', - ), - ), - ); - - self::$time_periods = array( - array( - 'seconds' => YEAR_IN_SECONDS, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ), - ), - array( - 'seconds' => MONTH_IN_SECONDS, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ), - ), - array( - 'seconds' => WEEK_IN_SECONDS, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ), - ), - array( - 'seconds' => DAY_IN_SECONDS, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ), - ), - array( - 'seconds' => HOUR_IN_SECONDS, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ), - ), - array( - 'seconds' => MINUTE_IN_SECONDS, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ), - ), - array( - 'seconds' => 1, - /* translators: %s: amount of time */ - 'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ), - ), - ); - - parent::__construct( array( - 'singular' => 'action-scheduler', - 'plural' => 'action-scheduler', - 'ajax' => false, - ) ); - } - - /** - * Convert an interval of seconds into a two part human friendly string. - * - * The WordPress human_time_diff() function only calculates the time difference to one degree, meaning - * even if an action is 1 day and 11 hours away, it will display "1 day". This function goes one step - * further to display two degrees of accuracy. - * - * Inspired by the Crontrol::interval() function by Edward Dale: https://wordpress.org/plugins/wp-crontrol/ - * - * @param int $interval A interval in seconds. - * @param int $periods_to_include Depth of time periods to include, e.g. for an interval of 70, and $periods_to_include of 2, both minutes and seconds would be included. With a value of 1, only minutes would be included. - * @return string A human friendly string representation of the interval. - */ - private static function human_interval( $interval, $periods_to_include = 2 ) { - - if ( $interval <= 0 ) { - return __( 'Now!', 'action-scheduler' ); - } - - $output = ''; - - for ( $time_period_index = 0, $periods_included = 0, $seconds_remaining = $interval; $time_period_index < count( self::$time_periods ) && $seconds_remaining > 0 && $periods_included < $periods_to_include; $time_period_index++ ) { - - $periods_in_interval = floor( $seconds_remaining / self::$time_periods[ $time_period_index ]['seconds'] ); - - if ( $periods_in_interval > 0 ) { - if ( ! empty( $output ) ) { - $output .= ' '; - } - $output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'action-scheduler' ), $periods_in_interval ); - $seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds']; - $periods_included++; - } - } - - return $output; - } - - /** - * Returns the recurrence of an action or 'Non-repeating'. The output is human readable. - * - * @param ActionScheduler_Action $action - * - * @return string - */ - protected function get_recurrence( $action ) { - $schedule = $action->get_schedule(); - if ( $schedule->is_recurring() ) { - $recurrence = $schedule->get_recurrence(); - - if ( is_numeric( $recurrence ) ) { - /* translators: %s: time interval */ - return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence ) ); - } else { - return $recurrence; - } - } - - return __( 'Non-repeating', 'action-scheduler' ); - } - - /** - * Serializes the argument of an action to render it in a human friendly format. - * - * @param array $row The array representation of the current row of the table - * - * @return string - */ - public function column_args( array $row ) { - if ( empty( $row['args'] ) ) { - return ''; - } - - $row_html = '
      '; - foreach ( $row['args'] as $key => $value ) { - $row_html .= sprintf( '
    • %s => %s
    • ', esc_html( var_export( $key, true ) ), esc_html( var_export( $value, true ) ) ); - } - $row_html .= '
    '; - - return apply_filters( 'action_scheduler_list_table_column_args', $row_html, $row ); - } - - /** - * Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal. - * - * @param array $row Action array. - * @return string - */ - public function column_log_entries( array $row ) { - - $log_entries_html = '
      '; - - $timezone = new DateTimezone( 'UTC' ); - - foreach ( $row['log_entries'] as $log_entry ) { - $log_entries_html .= $this->get_log_entry_html( $log_entry, $timezone ); - } - - $log_entries_html .= '
    '; - - return $log_entries_html; - } - - /** - * Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal. - * - * @param ActionScheduler_LogEntry $log_entry - * @param DateTimezone $timezone - * @return string - */ - protected function get_log_entry_html( ActionScheduler_LogEntry $log_entry, DateTimezone $timezone ) { - $date = $log_entry->get_date(); - $date->setTimezone( $timezone ); - return sprintf( '
  • %s
    %s
  • ', esc_html( $date->format( 'Y-m-d H:i:s O' ) ), esc_html( $log_entry->get_message() ) ); - } - - /** - * Only display row actions for pending actions. - * - * @param array $row Row to render - * @param string $column_name Current row - * - * @return string - */ - protected function maybe_render_actions( $row, $column_name ) { - if ( 'pending' === strtolower( $row['status'] ) ) { - return parent::maybe_render_actions( $row, $column_name ); - } - - return ''; - } - - /** - * Renders admin notifications - * - * Notifications: - * 1. When the maximum number of tasks are being executed simultaneously - * 2. Notifications when a task us manually executed - */ - public function display_admin_notices() { - - if ( $this->runner->has_maximum_concurrent_batches() ) { - $this->admin_notices[] = array( - 'class' => 'updated', - 'message' => sprintf( - /* translators: %s: amount of claims */ - __( 'Maximum simultaneous queues already in progress (%s queues). No additional queues will begin processing until the current queues are complete.', 'action-scheduler' ), - $this->store->get_claim_count() - ), - ); - } elseif ( $this->store->has_pending_actions_due() ) { - - $async_request_lock_expiration = ActionScheduler::lock()->get_expiration( 'async-request-runner' ); - - // No lock set or lock expired - if ( false === $async_request_lock_expiration || $async_request_lock_expiration < time() ) { - $in_progress_url = add_query_arg( 'status', 'in-progress', remove_query_arg( 'status' ) ); - /* translators: %s: process URL */ - $async_request_message = sprintf( __( 'A new queue has begun processing. View actions in-progress »', 'action-scheduler' ), esc_url( $in_progress_url ) ); - } else { - /* translators: %d: seconds */ - $async_request_message = sprintf( __( 'The next queue will begin processing in approximately %d seconds.', 'action-scheduler' ), $async_request_lock_expiration - time() ); - } - - $this->admin_notices[] = array( - 'class' => 'notice notice-info', - 'message' => $async_request_message, - ); - } - - $notification = get_transient( 'action_scheduler_admin_notice' ); - - if ( is_array( $notification ) ) { - delete_transient( 'action_scheduler_admin_notice' ); - - $action = $this->store->fetch_action( $notification['action_id'] ); - $action_hook_html = '' . $action->get_hook() . ''; - if ( 1 == $notification['success'] ) { - $class = 'updated'; - switch ( $notification['row_action_type'] ) { - case 'run' : - /* translators: %s: action HTML */ - $action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html ); - break; - case 'cancel' : - /* translators: %s: action HTML */ - $action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html ); - break; - default : - /* translators: %s: action HTML */ - $action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html ); - break; - } - } else { - $class = 'error'; - /* translators: 1: action HTML 2: action ID 3: error message */ - $action_message_html = sprintf( __( 'Could not process change for action: "%1$s" (ID: %2$d). Error: %3$s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) ); - } - - $action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification ); - - $this->admin_notices[] = array( - 'class' => $class, - 'message' => $action_message_html, - ); - } - - parent::display_admin_notices(); - } - - /** - * Prints the scheduled date in a human friendly format. - * - * @param array $row The array representation of the current row of the table - * - * @return string - */ - public function column_schedule( $row ) { - return $this->get_schedule_display_string( $row['schedule'] ); - } - - /** - * Get the scheduled date in a human friendly format. - * - * @param ActionScheduler_Schedule $schedule - * @return string - */ - protected function get_schedule_display_string( ActionScheduler_Schedule $schedule ) { - - $schedule_display_string = ''; - - if ( ! $schedule->get_date() ) { - return '0000-00-00 00:00:00'; - } - - $next_timestamp = $schedule->get_date()->getTimestamp(); - - $schedule_display_string .= $schedule->get_date()->format( 'Y-m-d H:i:s O' ); - $schedule_display_string .= '
    '; - - if ( gmdate( 'U' ) > $next_timestamp ) { - /* translators: %s: date interval */ - $schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) ); - } else { - /* translators: %s: date interval */ - $schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) ); - } - - return $schedule_display_string; - } - - /** - * Bulk delete - * - * Deletes actions based on their ID. This is the handler for the bulk delete. It assumes the data - * properly validated by the callee and it will delete the actions without any extra validation. - * - * @param array $ids - * @param string $ids_sql Inherited and unused - */ - protected function bulk_delete( array $ids, $ids_sql ) { - foreach ( $ids as $id ) { - $this->store->delete_action( $id ); - } - } - - /** - * Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their - * parameters are valid. - * - * @param int $action_id - */ - protected function row_action_cancel( $action_id ) { - $this->process_row_action( $action_id, 'cancel' ); - } - - /** - * Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their - * parameters are valid. - * - * @param int $action_id - */ - protected function row_action_run( $action_id ) { - $this->process_row_action( $action_id, 'run' ); - } - - /** - * Implements the logic behind processing an action once an action link is clicked on the list table. - * - * @param int $action_id - * @param string $row_action_type The type of action to perform on the action. - */ - protected function process_row_action( $action_id, $row_action_type ) { - try { - switch ( $row_action_type ) { - case 'run' : - $this->runner->process_action( $action_id, 'Admin List Table' ); - break; - case 'cancel' : - $this->store->cancel_action( $action_id ); - break; - } - $success = 1; - $error_message = ''; - } catch ( Exception $e ) { - $success = 0; - $error_message = $e->getMessage(); - } - - set_transient( 'action_scheduler_admin_notice', compact( 'action_id', 'success', 'error_message', 'row_action_type' ), 30 ); - } - - /** - * {@inheritDoc} - */ - public function prepare_items() { - $this->prepare_column_headers(); - - $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page ); - $query = array( - 'per_page' => $per_page, - 'offset' => $this->get_items_offset(), - 'status' => $this->get_request_status(), - 'orderby' => $this->get_request_orderby(), - 'order' => $this->get_request_order(), - 'search' => $this->get_request_search_query(), - ); - - $this->items = array(); - - $total_items = $this->store->query_actions( $query, 'count' ); - - $status_labels = $this->store->get_status_labels(); - - foreach ( $this->store->query_actions( $query ) as $action_id ) { - try { - $action = $this->store->fetch_action( $action_id ); - } catch ( Exception $e ) { - continue; - } - $this->items[ $action_id ] = array( - 'ID' => $action_id, - 'hook' => $action->get_hook(), - 'status' => $status_labels[ $this->store->get_status( $action_id ) ], - 'args' => $action->get_args(), - 'group' => $action->get_group(), - 'log_entries' => $this->logger->get_logs( $action_id ), - 'claim_id' => $this->store->get_claim_id( $action_id ), - 'recurrence' => $this->get_recurrence( $action ), - 'schedule' => $action->get_schedule(), - ); - } - - $this->set_pagination_args( array( - 'total_items' => $total_items, - 'per_page' => $per_page, - 'total_pages' => ceil( $total_items / $per_page ), - ) ); - } - - /** - * Prints the available statuses so the user can click to filter. - */ - protected function display_filter_by_status() { - $this->status_counts = $this->store->action_counts(); - parent::display_filter_by_status(); - } - - /** - * Get the text to display in the search box on the list table. - */ - protected function get_search_box_button_text() { - return __( 'Search hook, args and claim ID', 'action-scheduler' ); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_LogEntry.php b/includes/libraries/action-scheduler/classes/ActionScheduler_LogEntry.php deleted file mode 100644 index 649636d..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_LogEntry.php +++ /dev/null @@ -1,67 +0,0 @@ -comment_type - * to ActionScheduler_LogEntry::__construct(), goodness knows why, and the Follow-up Emails plugin - * hard-codes loading its own version of ActionScheduler_wpCommentLogger with that out-dated method, - * goodness knows why, so we need to guard against that here instead of using a DateTime type declaration - * for the constructor's 3rd param of $date and causing a fatal error with older versions of FUE. - */ - if ( null !== $date && ! is_a( $date, 'DateTime' ) ) { - _doing_it_wrong( __METHOD__, 'The third parameter must be a valid DateTime instance, or null.', '2.0.0' ); - $date = null; - } - - $this->action_id = $action_id; - $this->message = $message; - $this->date = $date ? $date : new Datetime; - } - - /** - * Returns the date when this log entry was created - * - * @return Datetime - */ - public function get_date() { - return $this->date; - } - - public function get_action_id() { - return $this->action_id; - } - - public function get_message() { - return $this->message; - } -} - diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_NullLogEntry.php b/includes/libraries/action-scheduler/classes/ActionScheduler_NullLogEntry.php deleted file mode 100644 index 6f8f218..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_NullLogEntry.php +++ /dev/null @@ -1,11 +0,0 @@ -maybe_dispatch_async_request() uses a lock to avoid - * calling ActionScheduler_QueueRunner->has_maximum_concurrent_batches() every time the 'shutdown', - * hook is triggered, because that method calls ActionScheduler_QueueRunner->store->get_claim_count() - * to find the current number of claims in the database. - * - * @param string $lock_type A string to identify different lock types. - * @bool True if lock value has changed, false if not or if set failed. - */ - public function set( $lock_type ) { - return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) ); - } - - /** - * If a lock is set, return the timestamp it was set to expiry. - * - * @param string $lock_type A string to identify different lock types. - * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire. - */ - public function get_expiration( $lock_type ) { - return get_option( $this->get_key( $lock_type ) ); - } - - /** - * Get the key to use for storing the lock in the transient - * - * @param string $lock_type A string to identify different lock types. - * @return string - */ - protected function get_key( $lock_type ) { - return sprintf( 'action_scheduler_lock_%s', $lock_type ); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_QueueCleaner.php b/includes/libraries/action-scheduler/classes/ActionScheduler_QueueCleaner.php deleted file mode 100644 index 1da13ab..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_QueueCleaner.php +++ /dev/null @@ -1,155 +0,0 @@ -store = $store ? $store : ActionScheduler_Store::instance(); - $this->batch_size = $batch_size; - } - - public function delete_old_actions() { - $lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds ); - $cutoff = as_get_datetime_object($lifespan.' seconds ago'); - - $statuses_to_purge = array( - ActionScheduler_Store::STATUS_COMPLETE, - ActionScheduler_Store::STATUS_CANCELED, - ); - - foreach ( $statuses_to_purge as $status ) { - $actions_to_delete = $this->store->query_actions( array( - 'status' => $status, - 'modified' => $cutoff, - 'modified_compare' => '<=', - 'per_page' => $this->get_batch_size(), - ) ); - - foreach ( $actions_to_delete as $action_id ) { - try { - $this->store->delete_action( $action_id ); - } catch ( Exception $e ) { - - /** - * Notify 3rd party code of exceptions when deleting a completed action older than the retention period - * - * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their - * actions. - * - * @since 2.0.0 - * - * @param int $action_id The scheduled actions ID in the data store - * @param Exception $e The exception thrown when attempting to delete the action from the data store - * @param int $lifespan The retention period, in seconds, for old actions - * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch - */ - do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) ); - } - } - } - } - - /** - * Unclaim pending actions that have not been run within a given time limit. - * - * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed - * as a parameter is 10x the time limit used for queue processing. - * - * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes). - */ - public function reset_timeouts( $time_limit = 300 ) { - $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit ); - if ( $timeout < 0 ) { - return; - } - $cutoff = as_get_datetime_object($timeout.' seconds ago'); - $actions_to_reset = $this->store->query_actions( array( - 'status' => ActionScheduler_Store::STATUS_PENDING, - 'modified' => $cutoff, - 'modified_compare' => '<=', - 'claimed' => true, - 'per_page' => $this->get_batch_size(), - ) ); - - foreach ( $actions_to_reset as $action_id ) { - $this->store->unclaim_action( $action_id ); - do_action( 'action_scheduler_reset_action', $action_id ); - } - } - - /** - * Mark actions that have been running for more than a given time limit as failed, based on - * the assumption some uncatachable and unloggable fatal error occurred during processing. - * - * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed - * as a parameter is 10x the time limit used for queue processing. - * - * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes). - */ - public function mark_failures( $time_limit = 300 ) { - $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit ); - if ( $timeout < 0 ) { - return; - } - $cutoff = as_get_datetime_object($timeout.' seconds ago'); - $actions_to_reset = $this->store->query_actions( array( - 'status' => ActionScheduler_Store::STATUS_RUNNING, - 'modified' => $cutoff, - 'modified_compare' => '<=', - 'per_page' => $this->get_batch_size(), - ) ); - - foreach ( $actions_to_reset as $action_id ) { - $this->store->mark_failure( $action_id ); - do_action( 'action_scheduler_failed_action', $action_id, $timeout ); - } - } - - /** - * Do all of the cleaning actions. - * - * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes). - * @author Jeremy Pry - */ - public function clean( $time_limit = 300 ) { - $this->delete_old_actions(); - $this->reset_timeouts( $time_limit ); - $this->mark_failures( $time_limit ); - } - - /** - * Get the batch size for cleaning the queue. - * - * @author Jeremy Pry - * @return int - */ - protected function get_batch_size() { - /** - * Filter the batch size when cleaning the queue. - * - * @param int $batch_size The number of actions to clean in one batch. - */ - return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) ); - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php b/includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php deleted file mode 100644 index 25073c7..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php +++ /dev/null @@ -1,185 +0,0 @@ -store ); - } - - $this->async_request = $async_request; - } - - /** - * @codeCoverageIgnore - */ - public function init() { - - add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) ); - - $cron_context = array( 'WP Cron' ); - - if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) { - - // Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param - $next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK ); - if ( $next_timestamp ) { - wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK ); - } - - $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE ); - wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context ); - } - - add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) ); - - add_filter( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) ); - } - - /** - * Check if we should dispatch an async request to process actions. - * - * This method is attached to 'shutdown', so is called frequently. To avoid slowing down - * the site, it mitigates the work performed in each request by: - * 1. checking if it's in the admin context and then - * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default) - * 3. haven't exceeded the number of allowed batches. - * - * The order of these checks is important, because they run from a check on a value: - * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant - * 2. in memory - transients use autoloaded options by default - * 3. from a database query - has_maximum_concurrent_batches() run the query - * $this->store->get_claim_count() to find the current number of claims in the DB. - * - * If all of these conditions are met, then we request an async runner check whether it - * should dispatch a request to process pending actions. - */ - public function maybe_dispatch_async_request() { - if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) { - // Only start an async queue at most once every 60 seconds - ActionScheduler::lock()->set( 'async-request-runner' ); - $this->async_request->maybe_dispatch(); - } - } - - /** - * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue' - * - * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0 - * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context - * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK, - * should set a context as the first parameter. For an example of this, refer to the code seen in - * @see ActionScheduler_AsyncRequest_QueueRunner::handle() - * - * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' - * Generally, this should be capitalised and not localised as it's a proper noun. - * @return int The number of actions processed. - */ - public function run( $context = 'WP Cron' ) { - ActionScheduler_Compatibility::raise_memory_limit(); - ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() ); - do_action( 'action_scheduler_before_process_queue' ); - $this->run_cleanup(); - $processed_actions = 0; - if ( false === $this->has_maximum_concurrent_batches() ) { - $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 ); - do { - $processed_actions_in_batch = $this->do_batch( $batch_size, $context ); - $processed_actions += $processed_actions_in_batch; - } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory - } - - do_action( 'action_scheduler_after_process_queue' ); - return $processed_actions; - } - - /** - * Process a batch of actions pending in the queue. - * - * Actions are processed by claiming a set of pending actions then processing each one until either the batch - * size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded(). - * - * @param int $size The maximum number of actions to process in the batch. - * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' - * Generally, this should be capitalised and not localised as it's a proper noun. - * @return int The number of actions processed. - */ - protected function do_batch( $size = 100, $context = '' ) { - $claim = $this->store->stake_claim($size); - $this->monitor->attach($claim); - $processed_actions = 0; - - foreach ( $claim->get_actions() as $action_id ) { - // bail if we lost the claim - if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) { - break; - } - $this->process_action( $action_id, $context ); - $processed_actions++; - - if ( $this->batch_limits_exceeded( $processed_actions ) ) { - break; - } - } - $this->store->release_claim($claim); - $this->monitor->detach(); - $this->clear_caches(); - return $processed_actions; - } - - /** - * Running large batches can eat up memory, as WP adds data to its object cache. - * - * If using a persistent object store, this has the side effect of flushing that - * as well, so this is disabled by default. To enable: - * - * add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' ); - */ - protected function clear_caches() { - if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) { - wp_cache_flush(); - } - } - - public function add_wp_cron_schedule( $schedules ) { - $schedules['every_minute'] = array( - 'interval' => 60, // in seconds - 'display' => __( 'Every minute', 'action-scheduler' ), - ); - - return $schedules; - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_Versions.php b/includes/libraries/action-scheduler/classes/ActionScheduler_Versions.php deleted file mode 100644 index 915c2e6..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_Versions.php +++ /dev/null @@ -1,62 +0,0 @@ -versions[$version_string]) ) { - return FALSE; - } - $this->versions[$version_string] = $initialization_callback; - return TRUE; - } - - public function get_versions() { - return $this->versions; - } - - public function latest_version() { - $keys = array_keys($this->versions); - if ( empty($keys) ) { - return false; - } - uasort( $keys, 'version_compare' ); - return end($keys); - } - - public function latest_version_callback() { - $latest = $this->latest_version(); - if ( empty($latest) || !isset($this->versions[$latest]) ) { - return '__return_null'; - } - return $this->versions[$latest]; - } - - /** - * @return ActionScheduler_Versions - * @codeCoverageIgnore - */ - public static function instance() { - if ( empty(self::$instance) ) { - self::$instance = new self(); - } - return self::$instance; - } - - /** - * @codeCoverageIgnore - */ - public static function initialize_latest_version() { - $self = self::instance(); - call_user_func($self->latest_version_callback()); - } -} - \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php b/includes/libraries/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php deleted file mode 100644 index ceef177..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php +++ /dev/null @@ -1,108 +0,0 @@ - Status administration screen - add_action( 'load-tools_page_action-scheduler', array( __CLASS__, 'print_admin_notice' ) ); - add_action( 'load-woocommerce_page_wc-status', array( __CLASS__, 'print_admin_notice' ) ); - } - - /** - * Determines if there are log entries in the wp comments table. - * - * Uses the flag set on migration completion set by @see self::maybe_schedule_cleanup(). - * - * @return boolean Whether there are scheduled action comments in the comments table. - */ - public static function has_logs() { - return 'yes' === get_option( self::$has_logs_option_key ); - } - - /** - * Schedules the WP Post comment table cleanup to run in 6 months if it's not already scheduled. - * Attached to the migration complete hook 'action_scheduler/migration_complete'. - */ - public static function maybe_schedule_cleanup() { - if ( (bool) get_comments( array( 'type' => ActionScheduler_wpCommentLogger::TYPE, 'number' => 1, 'fields' => 'ids' ) ) ) { - update_option( self::$has_logs_option_key, 'yes' ); - - if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) { - as_schedule_single_action( gmdate( 'U' ) + ( 6 * MONTH_IN_SECONDS ), self::$cleanup_hook ); - } - } - } - - /** - * Delete all action comments from the WP Comments table. - */ - public static function delete_all_action_comments() { - global $wpdb; - $wpdb->delete( $wpdb->comments, array( 'comment_type' => ActionScheduler_wpCommentLogger::TYPE, 'comment_agent' => ActionScheduler_wpCommentLogger::AGENT ) ); - delete_option( self::$has_logs_option_key ); - } - - /** - * Prints details about the orphaned action logs and includes information on where to learn more. - */ - public static function print_admin_notice() { - $next_cleanup_message = ''; - $next_scheduled_cleanup_hook = as_next_scheduled_action( self::$cleanup_hook ); - - if ( $next_scheduled_cleanup_hook ) { - /* translators: %s: date interval */ - $next_cleanup_message = sprintf( __( 'This data will be deleted in %s.', 'action-scheduler' ), human_time_diff( gmdate( 'U' ), $next_scheduled_cleanup_hook ) ); - } - - $notice = sprintf( - /* translators: 1: next cleanup message 2: github issue URL */ - __( 'Action Scheduler has migrated data to custom tables; however, orphaned log entries exist in the WordPress Comments table. %1$s Learn more »', 'action-scheduler' ), - $next_cleanup_message, - 'https://github.com/woocommerce/action-scheduler/issues/368' - ); - - echo '

    ' . wp_kses_post( $notice ) . '

    '; - } -} diff --git a/includes/libraries/action-scheduler/classes/ActionScheduler_wcSystemStatus.php b/includes/libraries/action-scheduler/classes/ActionScheduler_wcSystemStatus.php deleted file mode 100644 index 1fc7541..0000000 --- a/includes/libraries/action-scheduler/classes/ActionScheduler_wcSystemStatus.php +++ /dev/null @@ -1,147 +0,0 @@ -store = $store; - } - - /** - * Display action data, including number of actions grouped by status and the oldest & newest action in each status. - * - * Helpful to identify issues, like a clogged queue. - */ - public function render() { - $action_counts = $this->store->action_counts(); - $status_labels = $this->store->get_status_labels(); - $oldest_and_newest = $this->get_oldest_and_newest( array_keys( $status_labels ) ); - - $this->get_template( $status_labels, $action_counts, $oldest_and_newest ); - } - - /** - * Get oldest and newest scheduled dates for a given set of statuses. - * - * @param array $status_keys Set of statuses to find oldest & newest action for. - * @return array - */ - protected function get_oldest_and_newest( $status_keys ) { - - $oldest_and_newest = array(); - - foreach ( $status_keys as $status ) { - $oldest_and_newest[ $status ] = array( - 'oldest' => '–', - 'newest' => '–', - ); - - if ( 'in-progress' === $status ) { - continue; - } - - $oldest_and_newest[ $status ]['oldest'] = $this->get_action_status_date( $status, 'oldest' ); - $oldest_and_newest[ $status ]['newest'] = $this->get_action_status_date( $status, 'newest' ); - } - - return $oldest_and_newest; - } - - /** - * Get oldest or newest scheduled date for a given status. - * - * @param string $status Action status label/name string. - * @param string $date_type Oldest or Newest. - * @return DateTime - */ - protected function get_action_status_date( $status, $date_type = 'oldest' ) { - - $order = 'oldest' === $date_type ? 'ASC' : 'DESC'; - - $action = $this->store->query_actions( array( - 'claimed' => false, - 'status' => $status, - 'per_page' => 1, - 'order' => $order, - ) ); - - if ( ! empty( $action ) ) { - $date_object = $this->store->get_date( $action[0] ); - $action_date = $date_object->format( 'Y-m-d H:i:s O' ); - } else { - $action_date = '–'; - } - - return $action_date; - } - - /** - * Get oldest or newest scheduled date for a given status. - * - * @param array $status_labels Set of statuses to find oldest & newest action for. - * @param array $action_counts Number of actions grouped by status. - * @param array $oldest_and_newest Date of the oldest and newest action with each status. - */ - protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) { - ?> - - - - - - - - - - - - - - - - $count ) { - // WC uses the 3rd column for export, so we need to display more data in that (hidden when viewed as part of the table) and add an empty 2nd column. - printf( - '', - esc_html( $status_labels[ $status ] ), - number_format_i18n( $count ), - $oldest_and_newest[ $status ]['oldest'], - $oldest_and_newest[ $status ]['newest'] - ); - } - ?> - -

     
    %1$s %2$s, Oldest: %3$s, Newest: %4$s%3$s%4$s
    - - run_cleanup(); - $this->add_hooks(); - - // Check to make sure there aren't too many concurrent processes running. - if ( $this->has_maximum_concurrent_batches() ) { - if ( $force ) { - WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) ); - } else { - WP_CLI::error( __( 'There are too many concurrent batches.', 'action-scheduler' ) ); - } - } - - // Stake a claim and store it. - $this->claim = $this->store->stake_claim( $batch_size, null, $hooks, $group ); - $this->monitor->attach( $this->claim ); - $this->actions = $this->claim->get_actions(); - - return count( $this->actions ); - } - - /** - * Add our hooks to the appropriate actions. - * - * @author Jeremy Pry - */ - protected function add_hooks() { - add_action( 'action_scheduler_before_execute', array( $this, 'before_execute' ) ); - add_action( 'action_scheduler_after_execute', array( $this, 'after_execute' ), 10, 2 ); - add_action( 'action_scheduler_failed_execution', array( $this, 'action_failed' ), 10, 2 ); - } - - /** - * Set up the WP CLI progress bar. - * - * @author Jeremy Pry - */ - protected function setup_progress_bar() { - $count = count( $this->actions ); - $this->progress_bar = new ProgressBar( - /* translators: %d: amount of actions */ - sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ), - $count - ); - } - - /** - * Process actions in the queue. - * - * @author Jeremy Pry - * - * @param string $context Optional runner context. Default 'WP CLI'. - * - * @return int The number of actions processed. - */ - public function run( $context = 'WP CLI' ) { - do_action( 'action_scheduler_before_process_queue' ); - $this->setup_progress_bar(); - foreach ( $this->actions as $action_id ) { - // Error if we lost the claim. - if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $this->claim->get_id() ) ) ) { - WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'action-scheduler' ) ); - break; - } - - $this->process_action( $action_id, $context ); - $this->progress_bar->tick(); - } - - $completed = $this->progress_bar->current(); - $this->progress_bar->finish(); - $this->store->release_claim( $this->claim ); - do_action( 'action_scheduler_after_process_queue' ); - - return $completed; - } - - /** - * Handle WP CLI message when the action is starting. - * - * @author Jeremy Pry - * - * @param $action_id - */ - public function before_execute( $action_id ) { - /* translators: %s refers to the action ID */ - WP_CLI::log( sprintf( __( 'Started processing action %s', 'action-scheduler' ), $action_id ) ); - } - - /** - * Handle WP CLI message when the action has completed. - * - * @author Jeremy Pry - * - * @param int $action_id - * @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility. - */ - public function after_execute( $action_id, $action = null ) { - // backward compatibility - if ( null === $action ) { - $action = $this->store->fetch_action( $action_id ); - } - /* translators: 1: action ID 2: hook name */ - WP_CLI::log( sprintf( __( 'Completed processing action %1$s with hook: %2$s', 'action-scheduler' ), $action_id, $action->get_hook() ) ); - } - - /** - * Handle WP CLI message when the action has failed. - * - * @author Jeremy Pry - * - * @param int $action_id - * @param Exception $exception - * @throws \WP_CLI\ExitException With failure message. - */ - public function action_failed( $action_id, $exception ) { - WP_CLI::error( - /* translators: 1: action ID 2: exception message */ - sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ), - false - ); - } - - /** - * Sleep and help avoid hitting memory limit - * - * @param int $sleep_time Amount of seconds to sleep - * @deprecated 3.0.0 - */ - protected function stop_the_insanity( $sleep_time = 0 ) { - _deprecated_function( 'ActionScheduler_WPCLI_QueueRunner::stop_the_insanity', '3.0.0', 'ActionScheduler_DataController::free_memory' ); - - ActionScheduler_DataController::free_memory(); - } - - /** - * Maybe trigger the stop_the_insanity() method to free up memory. - */ - protected function maybe_stop_the_insanity() { - // The value returned by progress_bar->current() might be padded. Remove padding, and convert to int. - $current_iteration = intval( trim( $this->progress_bar->current() ) ); - if ( 0 === $current_iteration % 50 ) { - $this->stop_the_insanity(); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php b/includes/libraries/action-scheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php deleted file mode 100644 index c27008b..0000000 --- a/includes/libraries/action-scheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php +++ /dev/null @@ -1,158 +0,0 @@ -] - * : The maximum number of actions to run. Defaults to 100. - * - * [--batches=] - * : Limit execution to a number of batches. Defaults to 0, meaning batches will continue being executed until all actions are complete. - * - * [--cleanup-batch-size=] - * : The maximum number of actions to clean up. Defaults to the value of --batch-size. - * - * [--hooks=] - * : Only run actions with the specified hook. Omitting this option runs actions with any hook. Define multiple hooks as a comma separated string (without spaces), e.g. `--hooks=hook_one,hook_two,hook_three` - * - * [--group=] - * : Only run actions from the specified group. Omitting this option runs actions from all groups. - * - * [--free-memory-on=] - * : The number of actions to process between freeing memory. 0 disables freeing memory. Default 50. - * - * [--pause=] - * : The number of seconds to pause when freeing memory. Default no pause. - * - * [--force] - * : Whether to force execution despite the maximum number of concurrent processes being exceeded. - * - * @param array $args Positional arguments. - * @param array $assoc_args Keyed arguments. - * @throws \WP_CLI\ExitException When an error occurs. - * - * @subcommand run - */ - public function run( $args, $assoc_args ) { - // Handle passed arguments. - $batch = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batch-size', 100 ) ); - $batches = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batches', 0 ) ); - $clean = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'cleanup-batch-size', $batch ) ); - $hooks = explode( ',', WP_CLI\Utils\get_flag_value( $assoc_args, 'hooks', '' ) ); - $hooks = array_filter( array_map( 'trim', $hooks ) ); - $group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'group', '' ); - $free_on = \WP_CLI\Utils\get_flag_value( $assoc_args, 'free-memory-on', '' ); - $sleep = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pause', '' ); - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false ); - - ActionScheduler_DataController::set_free_ticks( $free_on ); - ActionScheduler_DataController::set_sleep_time( $sleep ); - - $batches_completed = 0; - $actions_completed = 0; - $unlimited = $batches === 0; - - try { - // Custom queue cleaner instance. - $cleaner = new ActionScheduler_QueueCleaner( null, $clean ); - - // Get the queue runner instance - $runner = new ActionScheduler_WPCLI_QueueRunner( null, null, $cleaner ); - - // Determine how many tasks will be run in the first batch. - $total = $runner->setup( $batch, $hooks, $group, $force ); - - // Run actions for as long as possible. - while ( $total > 0 ) { - $this->print_total_actions( $total ); - $actions_completed += $runner->run(); - $batches_completed++; - - // Maybe set up tasks for the next batch. - $total = ( $unlimited || $batches_completed < $batches ) ? $runner->setup( $batch, $hooks, $group, $force ) : 0; - } - } catch ( Exception $e ) { - $this->print_error( $e ); - } - - $this->print_total_batches( $batches_completed ); - $this->print_success( $actions_completed ); - } - - /** - * Print WP CLI message about how many actions are about to be processed. - * - * @author Jeremy Pry - * - * @param int $total - */ - protected function print_total_actions( $total ) { - WP_CLI::log( - sprintf( - /* translators: %d refers to how many scheduled taks were found to run */ - _n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'action-scheduler' ), - number_format_i18n( $total ) - ) - ); - } - - /** - * Print WP CLI message about how many batches of actions were processed. - * - * @author Jeremy Pry - * - * @param int $batches_completed - */ - protected function print_total_batches( $batches_completed ) { - WP_CLI::log( - sprintf( - /* translators: %d refers to the total number of batches executed */ - _n( '%d batch executed.', '%d batches executed.', $batches_completed, 'action-scheduler' ), - number_format_i18n( $batches_completed ) - ) - ); - } - - /** - * Convert an exception into a WP CLI error. - * - * @author Jeremy Pry - * - * @param Exception $e The error object. - * - * @throws \WP_CLI\ExitException - */ - protected function print_error( Exception $e ) { - WP_CLI::error( - sprintf( - /* translators: %s refers to the exception error message */ - __( 'There was an error running the action scheduler: %s', 'action-scheduler' ), - $e->getMessage() - ) - ); - } - - /** - * Print a success message with the number of completed actions. - * - * @author Jeremy Pry - * - * @param int $actions_completed - */ - protected function print_success( $actions_completed ) { - WP_CLI::success( - sprintf( - /* translators: %d refers to the total number of taskes completed */ - _n( '%d scheduled task completed.', '%d scheduled tasks completed.', $actions_completed, 'action-scheduler' ), - number_format_i18n( $actions_completed ) - ) - ); - } -} diff --git a/includes/libraries/action-scheduler/classes/WP_CLI/Migration_Command.php b/includes/libraries/action-scheduler/classes/WP_CLI/Migration_Command.php deleted file mode 100644 index 066697e..0000000 --- a/includes/libraries/action-scheduler/classes/WP_CLI/Migration_Command.php +++ /dev/null @@ -1,148 +0,0 @@ - 'Migrates actions to the DB tables store', - 'synopsis' => [ - [ - 'type' => 'assoc', - 'name' => 'batch-size', - 'optional' => true, - 'default' => 100, - 'description' => 'The number of actions to process in each batch', - ], - [ - 'type' => 'assoc', - 'name' => 'free-memory-on', - 'optional' => true, - 'default' => 50, - 'description' => 'The number of actions to process between freeing memory. 0 disables freeing memory', - ], - [ - 'type' => 'assoc', - 'name' => 'pause', - 'optional' => true, - 'default' => 0, - 'description' => 'The number of seconds to pause when freeing memory', - ], - [ - 'type' => 'flag', - 'name' => 'dry-run', - 'optional' => true, - 'description' => 'Reports on the actions that would have been migrated, but does not change any data', - ], - ], - ] ); - } - - /** - * Process the data migration. - * - * @param array $positional_args Required for WP CLI. Not used in migration. - * @param array $assoc_args Optional arguments. - * - * @return void - */ - public function migrate( $positional_args, $assoc_args ) { - $this->init_logging(); - - $config = $this->get_migration_config( $assoc_args ); - $runner = new Runner( $config ); - $runner->init_destination(); - - $batch_size = isset( $assoc_args[ 'batch-size' ] ) ? (int) $assoc_args[ 'batch-size' ] : 100; - $free_on = isset( $assoc_args[ 'free-memory-on' ] ) ? (int) $assoc_args[ 'free-memory-on' ] : 50; - $sleep = isset( $assoc_args[ 'pause' ] ) ? (int) $assoc_args[ 'pause' ] : 0; - \ActionScheduler_DataController::set_free_ticks( $free_on ); - \ActionScheduler_DataController::set_sleep_time( $sleep ); - - do { - $actions_processed = $runner->run( $batch_size ); - $this->total_processed += $actions_processed; - } while ( $actions_processed > 0 ); - - if ( ! $config->get_dry_run() ) { - // let the scheduler know that there's nothing left to do - $scheduler = new Scheduler(); - $scheduler->mark_complete(); - } - - WP_CLI::success( sprintf( '%s complete. %d actions processed.', $config->get_dry_run() ? 'Dry run' : 'Migration', $this->total_processed ) ); - } - - /** - * Build the config object used to create the Runner - * - * @param array $args Optional arguments. - * - * @return ActionScheduler\Migration\Config - */ - private function get_migration_config( $args ) { - $args = wp_parse_args( $args, [ - 'dry-run' => false, - ] ); - - $config = Controller::instance()->get_migration_config_object(); - $config->set_dry_run( ! empty( $args[ 'dry-run' ] ) ); - - return $config; - } - - /** - * Hook command line logging into migration actions. - */ - private function init_logging() { - add_action( 'action_scheduler/migrate_action_dry_run', function ( $action_id ) { - WP_CLI::debug( sprintf( 'Dry-run: migrated action %d', $action_id ) ); - }, 10, 1 ); - add_action( 'action_scheduler/no_action_to_migrate', function ( $action_id ) { - WP_CLI::debug( sprintf( 'No action found to migrate for ID %d', $action_id ) ); - }, 10, 1 ); - add_action( 'action_scheduler/migrate_action_failed', function ( $action_id ) { - WP_CLI::warning( sprintf( 'Failed migrating action with ID %d', $action_id ) ); - }, 10, 1 ); - add_action( 'action_scheduler/migrate_action_incomplete', function ( $source_id, $destination_id ) { - WP_CLI::warning( sprintf( 'Unable to remove source action with ID %d after migrating to new ID %d', $source_id, $destination_id ) ); - }, 10, 2 ); - add_action( 'action_scheduler/migrated_action', function ( $source_id, $destination_id ) { - WP_CLI::debug( sprintf( 'Migrated source action with ID %d to new store with ID %d', $source_id, $destination_id ) ); - }, 10, 2 ); - add_action( 'action_scheduler/migration_batch_starting', function ( $batch ) { - WP_CLI::debug( 'Beginning migration of batch: ' . print_r( $batch, true ) ); - }, 10, 1 ); - add_action( 'action_scheduler/migration_batch_complete', function ( $batch ) { - WP_CLI::log( sprintf( 'Completed migration of %d actions', count( $batch ) ) ); - }, 10, 1 ); - } -} diff --git a/includes/libraries/action-scheduler/classes/WP_CLI/ProgressBar.php b/includes/libraries/action-scheduler/classes/WP_CLI/ProgressBar.php deleted file mode 100644 index c86c74e..0000000 --- a/includes/libraries/action-scheduler/classes/WP_CLI/ProgressBar.php +++ /dev/null @@ -1,119 +0,0 @@ -total_ticks = 0; - $this->message = $message; - $this->count = $count; - $this->interval = $interval; - } - - /** - * Increment the progress bar ticks. - */ - public function tick() { - if ( null === $this->progress_bar ) { - $this->setup_progress_bar(); - } - - $this->progress_bar->tick(); - $this->total_ticks++; - - do_action( 'action_scheduler/progress_tick', $this->total_ticks ); - } - - /** - * Get the progress bar tick count. - * - * @return int - */ - public function current() { - return $this->progress_bar ? $this->progress_bar->current() : 0; - } - - /** - * Finish the current progress bar. - */ - public function finish() { - if ( null !== $this->progress_bar ) { - $this->progress_bar->finish(); - } - - $this->progress_bar = null; - } - - /** - * Set the message used when creating the progress bar. - * - * @param string $message The message to be used when the next progress bar is created. - */ - public function set_message( $message ) { - $this->message = $message; - } - - /** - * Set the count for a new progress bar. - * - * @param integer $count The total number of ticks expected to complete. - */ - public function set_count( $count ) { - $this->count = $count; - $this->finish(); - } - - /** - * Set up the progress bar. - */ - protected function setup_progress_bar() { - $this->progress_bar = \WP_CLI\Utils\make_progress_bar( - $this->message, - $this->count, - $this->interval - ); - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler.php deleted file mode 100644 index f009e42..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler.php +++ /dev/null @@ -1,269 +0,0 @@ -allow_migration() ) { - $command = new Migration_Command(); - $command->register(); - } - } - - /** - * Handle WP comment cleanup after migration. - */ - if ( is_a( $logger, 'ActionScheduler_DBLogger' ) && ActionScheduler_DataController::is_migration_complete() && ActionScheduler_WPCommentCleaner::has_logs() ) { - ActionScheduler_WPCommentCleaner::init(); - } - - add_action( 'action_scheduler/migration_complete', 'ActionScheduler_WPCommentCleaner::maybe_schedule_cleanup' ); - } - - /** - * Determine if the class is one of our abstract classes. - * - * @since 3.0.0 - * - * @param string $class The class name. - * - * @return bool - */ - protected static function is_class_abstract( $class ) { - static $abstracts = array( - 'ActionScheduler' => true, - 'ActionScheduler_Abstract_ListTable' => true, - 'ActionScheduler_Abstract_QueueRunner' => true, - 'ActionScheduler_Abstract_Schedule' => true, - 'ActionScheduler_Abstract_RecurringSchedule' => true, - 'ActionScheduler_Lock' => true, - 'ActionScheduler_Logger' => true, - 'ActionScheduler_Abstract_Schema' => true, - 'ActionScheduler_Store' => true, - 'ActionScheduler_TimezoneHelper' => true, - ); - - return isset( $abstracts[ $class ] ) && $abstracts[ $class ]; - } - - /** - * Determine if the class is one of our migration classes. - * - * @since 3.0.0 - * - * @param string $class The class name. - * - * @return bool - */ - protected static function is_class_migration( $class ) { - static $migration_segments = array( - 'ActionMigrator' => true, - 'BatchFetcher' => true, - 'DBStoreMigrator' => true, - 'DryRun' => true, - 'LogMigrator' => true, - 'Config' => true, - 'Controller' => true, - 'Runner' => true, - 'Scheduler' => true, - ); - - $segments = explode( '_', $class ); - $segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class; - - return isset( $migration_segments[ $segment ] ) && $migration_segments[ $segment ]; - } - - /** - * Determine if the class is one of our WP CLI classes. - * - * @since 3.0.0 - * - * @param string $class The class name. - * - * @return bool - */ - protected static function is_class_cli( $class ) { - static $cli_segments = array( - 'QueueRunner' => true, - 'Command' => true, - 'ProgressBar' => true, - ); - - $segments = explode( '_', $class ); - $segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class; - - return isset( $cli_segments[ $segment ] ) && $cli_segments[ $segment ]; - } - - final public function __clone() { - trigger_error("Singleton. No cloning allowed!", E_USER_ERROR); - } - - final public function __wakeup() { - trigger_error("Singleton. No serialization allowed!", E_USER_ERROR); - } - - final private function __construct() {} - - /** Deprecated **/ - - public static function get_datetime_object( $when = null, $timezone = 'UTC' ) { - _deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' ); - return as_get_datetime_object( $when, $timezone ); - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php deleted file mode 100644 index fc6520f..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php +++ /dev/null @@ -1,674 +0,0 @@ - value pair. The - * key must much the table column name and the value is the label, which is - * automatically translated. - */ - protected $columns = array(); - - /** - * Defines the row-actions. It expects an array where the key - * is the column name and the value is an array of actions. - * - * The array of actions are key => value, where key is the method name - * (with the prefix row_action_) and the value is the label - * and title. - */ - protected $row_actions = array(); - - /** - * The Primary key of our table - */ - protected $ID = 'ID'; - - /** - * Enables sorting, it expects an array - * of columns (the column names are the values) - */ - protected $sort_by = array(); - - protected $filter_by = array(); - - /** - * @var array The status name => count combinations for this table's items. Used to display status filters. - */ - protected $status_counts = array(); - - /** - * @var array Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ). - */ - protected $admin_notices = array(); - - /** - * @var string Localised string displayed in the

    element above the able. - */ - protected $table_header; - - /** - * Enables bulk actions. It must be an array where the key is the action name - * and the value is the label (which is translated automatically). It is important - * to notice that it will check that the method exists (`bulk_$name`) and will throw - * an exception if it does not exists. - * - * This class will automatically check if the current request has a bulk action, will do the - * validations and afterwards will execute the bulk method, with two arguments. The first argument - * is the array with primary keys, the second argument is a string with a list of the primary keys, - * escaped and ready to use (with `IN`). - */ - protected $bulk_actions = array(); - - /** - * Makes translation easier, it basically just wraps - * `_x` with some default (the package name). - * - * @deprecated 3.0.0 - */ - protected function translate( $text, $context = '' ) { - return $text; - } - - /** - * Reads `$this->bulk_actions` and returns an array that WP_List_Table understands. It - * also validates that the bulk method handler exists. It throws an exception because - * this is a library meant for developers and missing a bulk method is a development-time error. - */ - protected function get_bulk_actions() { - $actions = array(); - - foreach ( $this->bulk_actions as $action => $label ) { - if ( ! is_callable( array( $this, 'bulk_' . $action ) ) ) { - throw new RuntimeException( "The bulk action $action does not have a callback method" ); - } - - $actions[ $action ] = $label; - } - - return $actions; - } - - /** - * Checks if the current request has a bulk action. If that is the case it will validate and will - * execute the bulk method handler. Regardless if the action is valid or not it will redirect to - * the previous page removing the current arguments that makes this request a bulk action. - */ - protected function process_bulk_action() { - global $wpdb; - // Detect when a bulk action is being triggered. - $action = $this->current_action(); - - if ( ! $action ) { - return; - } - - check_admin_referer( 'bulk-' . $this->_args['plural'] ); - - $method = 'bulk_' . $action; - if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) { - $ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')'; - $this->$method( $_GET['ID'], $wpdb->prepare( $ids_sql, $_GET['ID'] ) ); - } - - wp_redirect( remove_query_arg( - array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ), - wp_unslash( $_SERVER['REQUEST_URI'] ) - ) ); - exit; - } - - /** - * Default code for deleting entries. We trust ids_sql because it is - * validated already by process_bulk_action() - */ - protected function bulk_delete( array $ids, $ids_sql ) { - global $wpdb; - - $wpdb->query( "DELETE FROM {$this->table_name} WHERE {$this->ID} IN $ids_sql" ); - } - - /** - * Prepares the _column_headers property which is used by WP_Table_List at rendering. - * It merges the columns and the sortable columns. - */ - protected function prepare_column_headers() { - $this->_column_headers = array( - $this->get_columns(), - array(), - $this->get_sortable_columns(), - ); - } - - /** - * Reads $this->sort_by and returns the columns name in a format that WP_Table_List - * expects - */ - public function get_sortable_columns() { - $sort_by = array(); - foreach ( $this->sort_by as $column ) { - $sort_by[ $column ] = array( $column, true ); - } - return $sort_by; - } - - /** - * Returns the columns names for rendering. It adds a checkbox for selecting everything - * as the first column - */ - public function get_columns() { - $columns = array_merge( - array( 'cb' => '' ), - $this->columns - ); - - return $columns; - } - - /** - * Get prepared LIMIT clause for items query - * - * @global wpdb $wpdb - * - * @return string Prepared LIMIT clause for items query. - */ - protected function get_items_query_limit() { - global $wpdb; - - $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page ); - return $wpdb->prepare( 'LIMIT %d', $per_page ); - } - - /** - * Returns the number of items to offset/skip for this current view. - * - * @return int - */ - protected function get_items_offset() { - $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page ); - $current_page = $this->get_pagenum(); - if ( 1 < $current_page ) { - $offset = $per_page * ( $current_page - 1 ); - } else { - $offset = 0; - } - - return $offset; - } - - /** - * Get prepared OFFSET clause for items query - * - * @global wpdb $wpdb - * - * @return string Prepared OFFSET clause for items query. - */ - protected function get_items_query_offset() { - global $wpdb; - - return $wpdb->prepare( 'OFFSET %d', $this->get_items_offset() ); - } - - /** - * Prepares the ORDER BY sql statement. It uses `$this->sort_by` to know which - * columns are sortable. This requests validates the orderby $_GET parameter is a valid - * column and sortable. It will also use order (ASC|DESC) using DESC by default. - */ - protected function get_items_query_order() { - if ( empty( $this->sort_by ) ) { - return ''; - } - - $orderby = esc_sql( $this->get_request_orderby() ); - $order = esc_sql( $this->get_request_order() ); - - return "ORDER BY {$orderby} {$order}"; - } - - /** - * Return the sortable column specified for this request to order the results by, if any. - * - * @return string - */ - protected function get_request_orderby() { - - $valid_sortable_columns = array_values( $this->sort_by ); - - if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns ) ) { - $orderby = sanitize_text_field( $_GET['orderby'] ); - } else { - $orderby = $valid_sortable_columns[0]; - } - - return $orderby; - } - - /** - * Return the sortable column order specified for this request. - * - * @return string - */ - protected function get_request_order() { - - if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( $_GET['order'] ) ) { - $order = 'DESC'; - } else { - $order = 'ASC'; - } - - return $order; - } - - /** - * Return the status filter for this request, if any. - * - * @return string - */ - protected function get_request_status() { - $status = ( ! empty( $_GET['status'] ) ) ? $_GET['status'] : ''; - return $status; - } - - /** - * Return the search filter for this request, if any. - * - * @return string - */ - protected function get_request_search_query() { - $search_query = ( ! empty( $_GET['s'] ) ) ? $_GET['s'] : ''; - return $search_query; - } - - /** - * Process and return the columns name. This is meant for using with SQL, this means it - * always includes the primary key. - * - * @return array - */ - protected function get_table_columns() { - $columns = array_keys( $this->columns ); - if ( ! in_array( $this->ID, $columns ) ) { - $columns[] = $this->ID; - } - - return $columns; - } - - /** - * Check if the current request is doing a "full text" search. If that is the case - * prepares the SQL to search texts using LIKE. - * - * If the current request does not have any search or if this list table does not support - * that feature it will return an empty string. - * - * TODO: - * - Improve search doing LIKE by word rather than by phrases. - * - * @return string - */ - protected function get_items_query_search() { - global $wpdb; - - if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) { - return ''; - } - - $filter = array(); - foreach ( $this->search_by as $column ) { - $filter[] = $wpdb->prepare('`' . $column . '` like "%%s%"', $wpdb->esc_like( $_GET['s'] )); - } - return implode( ' OR ', $filter ); - } - - /** - * Prepares the SQL to filter rows by the options defined at `$this->filter_by`. Before trusting - * any data sent by the user it validates that it is a valid option. - */ - protected function get_items_query_filters() { - global $wpdb; - - if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) { - return ''; - } - - $filter = array(); - - foreach ( $this->filter_by as $column => $options ) { - if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) { - continue; - } - - $filter[] = $wpdb->prepare( "`$column` = %s", $_GET['filter_by'][ $column ] ); - } - - return implode( ' AND ', $filter ); - - } - - /** - * Prepares the data to feed WP_Table_List. - * - * This has the core for selecting, sorting and filting data. To keep the code simple - * its logic is split among many methods (get_items_query_*). - * - * Beside populating the items this function will also count all the records that matches - * the filtering criteria and will do fill the pagination variables. - */ - public function prepare_items() { - global $wpdb; - - $this->process_bulk_action(); - - $this->process_row_actions(); - - if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) { - // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter - wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) ); - exit; - } - - $this->prepare_column_headers(); - - $limit = $this->get_items_query_limit(); - $offset = $this->get_items_query_offset(); - $order = $this->get_items_query_order(); - $where = array_filter(array( - $this->get_items_query_search(), - $this->get_items_query_filters(), - )); - $columns = '`' . implode( '`, `', $this->get_table_columns() ) . '`'; - - if ( ! empty( $where ) ) { - $where = 'WHERE ('. implode( ') AND (', $where ) . ')'; - } else { - $where = ''; - } - - $sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}"; - - $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) ); - - $query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}"; - $total_items = $wpdb->get_var( $query_count ); - $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page ); - $this->set_pagination_args( array( - 'total_items' => $total_items, - 'per_page' => $per_page, - 'total_pages' => ceil( $total_items / $per_page ), - ) ); - } - - public function extra_tablenav( $which ) { - if ( ! $this->filter_by || 'top' !== $which ) { - return; - } - - echo '
    '; - - foreach ( $this->filter_by as $id => $options ) { - $default = ! empty( $_GET['filter_by'][ $id ] ) ? $_GET['filter_by'][ $id ] : ''; - if ( empty( $options[ $default ] ) ) { - $default = ''; - } - - echo ''; - } - - submit_button( esc_html__( 'Filter', 'action-scheduler' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); - echo '
    '; - } - - /** - * Set the data for displaying. It will attempt to unserialize (There is a chance that some columns - * are serialized). This can be override in child classes for futher data transformation. - */ - protected function set_items( array $items ) { - $this->items = array(); - foreach ( $items as $item ) { - $this->items[ $item[ $this->ID ] ] = array_map( 'maybe_unserialize', $item ); - } - } - - /** - * Renders the checkbox for each row, this is the first column and it is named ID regardless - * of how the primary key is named (to keep the code simpler). The bulk actions will do the proper - * name transformation though using `$this->ID`. - */ - public function column_cb( $row ) { - return ''; - } - - /** - * Renders the row-actions. - * - * This method renders the action menu, it reads the definition from the $row_actions property, - * and it checks that the row action method exists before rendering it. - * - * @param array $row Row to render - * @param $column_name Current row - * @return - */ - protected function maybe_render_actions( $row, $column_name ) { - if ( empty( $this->row_actions[ $column_name ] ) ) { - return; - } - - $row_id = $row[ $this->ID ]; - - $actions = '
    '; - $action_count = 0; - foreach ( $this->row_actions[ $column_name ] as $action_key => $action ) { - - $action_count++; - - if ( ! method_exists( $this, 'row_action_' . $action_key ) ) { - continue; - } - - $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg( array( 'row_action' => $action_key, 'row_id' => $row_id, 'nonce' => wp_create_nonce( $action_key . '::' . $row_id ) ) ); - $span_class = ! empty( $action['class'] ) ? $action['class'] : $action_key; - $separator = ( $action_count < count( $this->row_actions[ $column_name ] ) ) ? ' | ' : ''; - - $actions .= sprintf( '', esc_attr( $span_class ) ); - $actions .= sprintf( '%3$s', esc_url( $action_link ), esc_attr( $action['desc'] ), esc_html( $action['name'] ) ); - $actions .= sprintf( '%s', $separator ); - } - $actions .= '
    '; - return $actions; - } - - protected function process_row_actions() { - $parameters = array( 'row_action', 'row_id', 'nonce' ); - foreach ( $parameters as $parameter ) { - if ( empty( $_REQUEST[ $parameter ] ) ) { - return; - } - } - - $method = 'row_action_' . $_REQUEST['row_action']; - - if ( $_REQUEST['nonce'] === wp_create_nonce( $_REQUEST[ 'row_action' ] . '::' . $_REQUEST[ 'row_id' ] ) && method_exists( $this, $method ) ) { - $this->$method( $_REQUEST['row_id'] ); - } - - wp_redirect( remove_query_arg( - array( 'row_id', 'row_action', 'nonce' ), - wp_unslash( $_SERVER['REQUEST_URI'] ) - ) ); - exit; - } - - /** - * Default column formatting, it will escape everythig for security. - */ - public function column_default( $item, $column_name ) { - $column_html = esc_html( $item[ $column_name ] ); - $column_html .= $this->maybe_render_actions( $item, $column_name ); - return $column_html; - } - - /** - * Display the table heading and search query, if any - */ - protected function display_header() { - echo '

    ' . esc_attr( $this->table_header ) . '

    '; - if ( $this->get_request_search_query() ) { - /* translators: %s: search query */ - echo '' . esc_attr( sprintf( __( 'Search results for "%s"', 'action-scheduler' ), $this->get_request_search_query() ) ) . ''; - } - echo '
    '; - } - - /** - * Display the table heading and search query, if any - */ - protected function display_admin_notices() { - foreach ( $this->admin_notices as $notice ) { - echo '
    '; - echo '

    ' . wp_kses_post( $notice['message'] ) . '

    '; - echo '
    '; - } - } - - /** - * Prints the available statuses so the user can click to filter. - */ - protected function display_filter_by_status() { - - $status_list_items = array(); - $request_status = $this->get_request_status(); - - // Helper to set 'all' filter when not set on status counts passed in - if ( ! isset( $this->status_counts['all'] ) ) { - $this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts; - } - - foreach ( $this->status_counts as $status_name => $count ) { - - if ( 0 === $count ) { - continue; - } - - if ( $status_name === $request_status || ( empty( $request_status ) && 'all' === $status_name ) ) { - $status_list_item = '
  • %3$s (%4$d)
  • '; - } else { - $status_list_item = '
  • %3$s (%4$d)
  • '; - } - - $status_filter_url = ( 'all' === $status_name ) ? remove_query_arg( 'status' ) : add_query_arg( 'status', $status_name ); - $status_list_items[] = sprintf( $status_list_item, esc_attr( $status_name ), esc_url( $status_filter_url ), esc_html( ucfirst( $status_name ) ), absint( $count ) ); - } - - if ( $status_list_items ) { - echo '
      '; - echo implode( " | \n", $status_list_items ); - echo '
    '; - } - } - - /** - * Renders the table list, we override the original class to render the table inside a form - * and to render any needed HTML (like the search box). By doing so the callee of a function can simple - * forget about any extra HTML. - */ - protected function display_table() { - echo '
    '; - foreach ( $_GET as $key => $value ) { - if ( '_' === $key[0] || 'paged' === $key ) { - continue; - } - echo ''; - } - if ( ! empty( $this->search_by ) ) { - echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // WPCS: XSS OK - } - parent::display(); - echo '
    '; - } - - /** - * Process any pending actions. - */ - public function process_actions() { - $this->process_bulk_action(); - - $this->process_row_actions(); - - if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) { - // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter - wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) ); - exit; - } - } - - /** - * Render the list table page, including header, notices, status filters and table. - */ - public function display_page() { - $this->prepare_items(); - - echo '
    '; - $this->display_header(); - $this->display_admin_notices(); - $this->display_filter_by_status(); - $this->display_table(); - echo '
    '; - } - - /** - * Get the text to display in the search box on the list table. - */ - protected function get_search_box_placeholder() { - return esc_html__( 'Search', 'action-scheduler' ); - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php deleted file mode 100644 index 7cfb3df..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php +++ /dev/null @@ -1,232 +0,0 @@ -created_time = microtime( true ); - - $this->store = $store ? $store : ActionScheduler_Store::instance(); - $this->monitor = $monitor ? $monitor : new ActionScheduler_FatalErrorMonitor( $this->store ); - $this->cleaner = $cleaner ? $cleaner : new ActionScheduler_QueueCleaner( $this->store ); - } - - /** - * Process an individual action. - * - * @param int $action_id The action ID to process. - * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' - * Generally, this should be capitalised and not localised as it's a proper noun. - */ - public function process_action( $action_id, $context = '' ) { - try { - do_action( 'action_scheduler_before_execute', $action_id, $context ); - - if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) { - do_action( 'action_scheduler_execution_ignored', $action_id, $context ); - return; - } - - $action = $this->store->fetch_action( $action_id ); - $this->store->log_execution( $action_id ); - $action->execute(); - do_action( 'action_scheduler_after_execute', $action_id, $action, $context ); - $this->store->mark_complete( $action_id ); - } catch ( Exception $e ) { - $this->store->mark_failure( $action_id ); - do_action( 'action_scheduler_failed_execution', $action_id, $e, $context ); - } - - if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) && $action->get_schedule()->is_recurring() ) { - $this->schedule_next_instance( $action, $action_id ); - } - } - - /** - * Schedule the next instance of the action if necessary. - * - * @param ActionScheduler_Action $action - * @param int $action_id - */ - protected function schedule_next_instance( ActionScheduler_Action $action, $action_id ) { - try { - ActionScheduler::factory()->repeat( $action ); - } catch ( Exception $e ) { - do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, $action ); - } - } - - /** - * Run the queue cleaner. - * - * @author Jeremy Pry - */ - protected function run_cleanup() { - $this->cleaner->clean( 10 * $this->get_time_limit() ); - } - - /** - * Get the number of concurrent batches a runner allows. - * - * @return int - */ - public function get_allowed_concurrent_batches() { - return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 1 ); - } - - /** - * Check if the number of allowed concurrent batches is met or exceeded. - * - * @return bool - */ - public function has_maximum_concurrent_batches() { - return $this->store->get_claim_count() >= $this->get_allowed_concurrent_batches(); - } - - /** - * Get the maximum number of seconds a batch can run for. - * - * @return int The number of seconds. - */ - protected function get_time_limit() { - - $time_limit = 30; - - // Apply deprecated filter from deprecated get_maximum_execution_time() method - if ( has_filter( 'action_scheduler_maximum_execution_time' ) ) { - _deprecated_function( 'action_scheduler_maximum_execution_time', '2.1.1', 'action_scheduler_queue_runner_time_limit' ); - $time_limit = apply_filters( 'action_scheduler_maximum_execution_time', $time_limit ); - } - - return absint( apply_filters( 'action_scheduler_queue_runner_time_limit', $time_limit ) ); - } - - /** - * Get the number of seconds the process has been running. - * - * @return int The number of seconds. - */ - protected function get_execution_time() { - $execution_time = microtime( true ) - $this->created_time; - - // Get the CPU time if the hosting environment uses it rather than wall-clock time to calculate a process's execution time. - if ( function_exists( 'getrusage' ) && apply_filters( 'action_scheduler_use_cpu_execution_time', defined( 'PANTHEON_ENVIRONMENT' ) ) ) { - $resource_usages = getrusage(); - - if ( isset( $resource_usages['ru_stime.tv_usec'], $resource_usages['ru_stime.tv_usec'] ) ) { - $execution_time = $resource_usages['ru_stime.tv_sec'] + ( $resource_usages['ru_stime.tv_usec'] / 1000000 ); - } - } - - return $execution_time; - } - - /** - * Check if the host's max execution time is (likely) to be exceeded if processing more actions. - * - * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action - * @return bool - */ - protected function time_likely_to_be_exceeded( $processed_actions ) { - - $execution_time = $this->get_execution_time(); - $max_execution_time = $this->get_time_limit(); - $time_per_action = $execution_time / $processed_actions; - $estimated_time = $execution_time + ( $time_per_action * 3 ); - $likely_to_be_exceeded = $estimated_time > $max_execution_time; - - return apply_filters( 'action_scheduler_maximum_execution_time_likely_to_be_exceeded', $likely_to_be_exceeded, $this, $processed_actions, $execution_time, $max_execution_time ); - } - - /** - * Get memory limit - * - * Based on WP_Background_Process::get_memory_limit() - * - * @return int - */ - protected function get_memory_limit() { - if ( function_exists( 'ini_get' ) ) { - $memory_limit = ini_get( 'memory_limit' ); - } else { - $memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce - } - - if ( ! $memory_limit || -1 === $memory_limit || '-1' === $memory_limit ) { - // Unlimited, set to 32GB. - $memory_limit = '32G'; - } - - return ActionScheduler_Compatibility::convert_hr_to_bytes( $memory_limit ); - } - - /** - * Memory exceeded - * - * Ensures the batch process never exceeds 90% of the maximum WordPress memory. - * - * Based on WP_Background_Process::memory_exceeded() - * - * @return bool - */ - protected function memory_exceeded() { - - $memory_limit = $this->get_memory_limit() * 0.90; - $current_memory = memory_get_usage( true ); - $memory_exceeded = $current_memory >= $memory_limit; - - return apply_filters( 'action_scheduler_memory_exceeded', $memory_exceeded, $this ); - } - - /** - * See if the batch limits have been exceeded, which is when memory usage is almost at - * the maximum limit, or the time to process more actions will exceed the max time limit. - * - * Based on WC_Background_Process::batch_limits_exceeded() - * - * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action - * @return bool - */ - protected function batch_limits_exceeded( $processed_actions ) { - return $this->memory_exceeded() || $this->time_likely_to_be_exceeded( $processed_actions ); - } - - /** - * Process actions in the queue. - * - * @author Jeremy Pry - * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' - * Generally, this should be capitalised and not localised as it's a proper noun. - * @return int The number of actions processed. - */ - abstract public function run( $context = '' ); -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php deleted file mode 100644 index 131d475..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php +++ /dev/null @@ -1,102 +0,0 @@ -start - and logic to calculate the next run date after - * that - @see $this->calculate_next(). The $first_date property also keeps a record of when the very - * first instance of this chain of schedules ran. - * - * @var DateTime - */ - private $first_date = NULL; - - /** - * Timestamp equivalent of @see $this->first_date - * - * @var int - */ - protected $first_timestamp = NULL; - - /** - * The recurrance between each time an action is run using this schedule. - * Used to calculate the start date & time. Can be a number of seconds, in the - * case of ActionScheduler_IntervalSchedule, or a cron expression, as in the - * case of ActionScheduler_CronSchedule. Or something else. - * - * @var mixed - */ - protected $recurrence; - - /** - * @param DateTime $date The date & time to run the action. - * @param mixed $recurrence The data used to determine the schedule's recurrance. - * @param DateTime|null $first (Optional) The date & time the first instance of this interval schedule ran. Default null, meaning this is the first instance. - */ - public function __construct( DateTime $date, $recurrence, DateTime $first = null ) { - parent::__construct( $date ); - $this->first_date = empty( $first ) ? $date : $first; - $this->recurrence = $recurrence; - } - - /** - * @return bool - */ - public function is_recurring() { - return true; - } - - /** - * Get the date & time of the first schedule in this recurring series. - * - * @return DateTime|null - */ - public function get_first_date() { - return clone $this->first_date; - } - - /** - * @return string - */ - public function get_recurrence() { - return $this->recurrence; - } - - /** - * For PHP 5.2 compat, since DateTime objects can't be serialized - * @return array - */ - public function __sleep() { - $sleep_params = parent::__sleep(); - $this->first_timestamp = $this->first_date->getTimestamp(); - return array_merge( $sleep_params, array( - 'first_timestamp', - 'recurrence' - ) ); - } - - /** - * Unserialize recurring schedules serialized/stored prior to AS 3.0.0 - * - * Prior to Action Scheduler 3.0.0, schedules used different property names to refer - * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp - * was the same as ActionScheduler_SimpleSchedule::timestamp. This was addressed in - * Action Scheduler 3.0.0, where properties and property names were aligned for better - * inheritance. To maintain backward compatibility with scheduled serialized and stored - * prior to 3.0, we need to correctly map the old property names. - */ - public function __wakeup() { - parent::__wakeup(); - if ( $this->first_timestamp > 0 ) { - $this->first_date = as_get_datetime_object( $this->first_timestamp ); - } else { - $this->first_date = $this->get_date(); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php deleted file mode 100644 index 2631ef5..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php +++ /dev/null @@ -1,83 +0,0 @@ -scheduled_date - * - * @var int - */ - protected $scheduled_timestamp = NULL; - - /** - * @param DateTime $date The date & time to run the action. - */ - public function __construct( DateTime $date ) { - $this->scheduled_date = $date; - } - - /** - * Check if a schedule should recur. - * - * @return bool - */ - abstract public function is_recurring(); - - /** - * Calculate when the next instance of this schedule would run based on a given date & time. - * - * @param DateTime $after - * @return DateTime - */ - abstract protected function calculate_next( DateTime $after ); - - /** - * Get the next date & time when this schedule should run after a given date & time. - * - * @param DateTime $after - * @return DateTime|null - */ - public function get_next( DateTime $after ) { - $after = clone $after; - if ( $after > $this->scheduled_date ) { - $after = $this->calculate_next( $after ); - return $after; - } - return clone $this->scheduled_date; - } - - /** - * Get the date & time the schedule is set to run. - * - * @return DateTime|null - */ - public function get_date() { - return $this->scheduled_date; - } - - /** - * For PHP 5.2 compat, since DateTime objects can't be serialized - * @return array - */ - public function __sleep() { - $this->scheduled_timestamp = $this->scheduled_date->getTimestamp(); - return array( - 'scheduled_timestamp', - ); - } - - public function __wakeup() { - $this->scheduled_date = as_get_datetime_object( $this->scheduled_timestamp ); - unset( $this->scheduled_timestamp ); - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php deleted file mode 100644 index f02c84d..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php +++ /dev/null @@ -1,133 +0,0 @@ -tables as $table ) { - $wpdb->tables[] = $table; - $name = $this->get_full_table_name( $table ); - $wpdb->$table = $name; - } - - // create the tables - if ( $this->schema_update_required() ) { - foreach ( $this->tables as $table ) { - $this->update_table( $table ); - } - $this->mark_schema_update_complete(); - } - } - - /** - * @param string $table The name of the table - * - * @return string The CREATE TABLE statement, suitable for passing to dbDelta - */ - abstract protected function get_table_definition( $table ); - - /** - * Determine if the database schema is out of date - * by comparing the integer found in $this->schema_version - * with the option set in the WordPress options table - * - * @return bool - */ - private function schema_update_required() { - $option_name = 'schema-' . static::class; - $version_found_in_db = get_option( $option_name, 0 ); - - // Check for schema option stored by the Action Scheduler Custom Tables plugin in case site has migrated from that plugin with an older schema - if ( 0 === $version_found_in_db ) { - - $plugin_option_name = 'schema-'; - - switch ( static::class ) { - case 'ActionScheduler_StoreSchema' : - $plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Store_Table_Maker'; - break; - case 'ActionScheduler_LoggerSchema' : - $plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Logger_Table_Maker'; - break; - } - - $version_found_in_db = get_option( $plugin_option_name, 0 ); - - delete_option( $plugin_option_name ); - } - - return version_compare( $version_found_in_db, $this->schema_version, '<' ); - } - - /** - * Update the option in WordPress to indicate that - * our schema is now up to date - * - * @return void - */ - private function mark_schema_update_complete() { - $option_name = 'schema-' . static::class; - - // work around race conditions and ensure that our option updates - $value_to_save = (string) $this->schema_version . '.0.' . time(); - - update_option( $option_name, $value_to_save ); - } - - /** - * Update the schema for the given table - * - * @param string $table The name of the table to update - * - * @return void - */ - private function update_table( $table ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $definition = $this->get_table_definition( $table ); - if ( $definition ) { - $updated = dbDelta( $definition ); - foreach ( $updated as $updated_table => $update_description ) { - if ( strpos( $update_description, 'Created table' ) === 0 ) { - do_action( 'action_scheduler/created_table', $updated_table, $table ); - } - } - } - } - - /** - * @param string $table - * - * @return string The full name of the table, including the - * table prefix for the current blog - */ - protected function get_full_table_name( $table ) { - return $GLOBALS[ 'wpdb' ]->prefix . $table; - } -} \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Lock.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Lock.php deleted file mode 100644 index 86e8528..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Lock.php +++ /dev/null @@ -1,62 +0,0 @@ -get_expiration( $lock_type ) >= time() ); - } - - /** - * Set a lock. - * - * @param string $lock_type A string to identify different lock types. - * @return bool - */ - abstract public function set( $lock_type ); - - /** - * If a lock is set, return the timestamp it was set to expiry. - * - * @param string $lock_type A string to identify different lock types. - * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire. - */ - abstract public function get_expiration( $lock_type ); - - /** - * Get the amount of time to set for a given lock. 60 seconds by default. - * - * @param string $lock_type A string to identify different lock types. - * @return int - */ - protected function get_duration( $lock_type ) { - return apply_filters( 'action_scheduler_lock_duration', self::$lock_duration, $lock_type ); - } - - /** - * @return ActionScheduler_Lock - */ - public static function instance() { - if ( empty( self::$locker ) ) { - $class = apply_filters( 'action_scheduler_lock_class', 'ActionScheduler_OptionLock' ); - self::$locker = new $class(); - } - return self::$locker; - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Logger.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Logger.php deleted file mode 100644 index f200195..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Logger.php +++ /dev/null @@ -1,176 +0,0 @@ -hook_stored_action(); - add_action( 'action_scheduler_canceled_action', array( $this, 'log_canceled_action' ), 10, 1 ); - add_action( 'action_scheduler_before_execute', array( $this, 'log_started_action' ), 10, 2 ); - add_action( 'action_scheduler_after_execute', array( $this, 'log_completed_action' ), 10, 3 ); - add_action( 'action_scheduler_failed_execution', array( $this, 'log_failed_action' ), 10, 3 ); - add_action( 'action_scheduler_failed_action', array( $this, 'log_timed_out_action' ), 10, 2 ); - add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_unexpected_shutdown' ), 10, 2 ); - add_action( 'action_scheduler_reset_action', array( $this, 'log_reset_action' ), 10, 1 ); - add_action( 'action_scheduler_execution_ignored', array( $this, 'log_ignored_action' ), 10, 2 ); - add_action( 'action_scheduler_failed_fetch_action', array( $this, 'log_failed_fetch_action' ), 10, 2 ); - add_action( 'action_scheduler_failed_to_schedule_next_instance', array( $this, 'log_failed_schedule_next_instance' ), 10, 2 ); - add_action( 'action_scheduler_bulk_cancel_actions', array( $this, 'bulk_log_cancel_actions' ), 10, 1 ); - } - - public function hook_stored_action() { - add_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ) ); - } - - public function unhook_stored_action() { - remove_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ) ); - } - - public function log_stored_action( $action_id ) { - $this->log( $action_id, __( 'action created', 'action-scheduler' ) ); - } - - public function log_canceled_action( $action_id ) { - $this->log( $action_id, __( 'action canceled', 'action-scheduler' ) ); - } - - public function log_started_action( $action_id, $context = '' ) { - if ( ! empty( $context ) ) { - /* translators: %s: context */ - $message = sprintf( __( 'action started via %s', 'action-scheduler' ), $context ); - } else { - $message = __( 'action started', 'action-scheduler' ); - } - $this->log( $action_id, $message ); - } - - public function log_completed_action( $action_id, $action = NULL, $context = '' ) { - if ( ! empty( $context ) ) { - /* translators: %s: context */ - $message = sprintf( __( 'action complete via %s', 'action-scheduler' ), $context ); - } else { - $message = __( 'action complete', 'action-scheduler' ); - } - $this->log( $action_id, $message ); - } - - public function log_failed_action( $action_id, Exception $exception, $context = '' ) { - if ( ! empty( $context ) ) { - /* translators: 1: context 2: exception message */ - $message = sprintf( __( 'action failed via %1$s: %2$s', 'action-scheduler' ), $context, $exception->getMessage() ); - } else { - /* translators: %s: exception message */ - $message = sprintf( __( 'action failed: %s', 'action-scheduler' ), $exception->getMessage() ); - } - $this->log( $action_id, $message ); - } - - public function log_timed_out_action( $action_id, $timeout ) { - /* translators: %s: amount of time */ - $this->log( $action_id, sprintf( __( 'action timed out after %s seconds', 'action-scheduler' ), $timeout ) ); - } - - public function log_unexpected_shutdown( $action_id, $error ) { - if ( ! empty( $error ) ) { - /* translators: 1: error message 2: filename 3: line */ - $this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %1$s in %2$s on line %3$s', 'action-scheduler' ), $error['message'], $error['file'], $error['line'] ) ); - } - } - - public function log_reset_action( $action_id ) { - $this->log( $action_id, __( 'action reset', 'action-scheduler' ) ); - } - - public function log_ignored_action( $action_id, $context = '' ) { - if ( ! empty( $context ) ) { - /* translators: %s: context */ - $message = sprintf( __( 'action ignored via %s', 'action-scheduler' ), $context ); - } else { - $message = __( 'action ignored', 'action-scheduler' ); - } - $this->log( $action_id, __( 'action ignored', 'action-scheduler' ) ); - } - - /** - * @param string $action_id - * @param Exception|NULL $exception The exception which occured when fetching the action. NULL by default for backward compatibility. - * - * @return ActionScheduler_LogEntry[] - */ - public function log_failed_fetch_action( $action_id, Exception $exception = NULL ) { - - if ( ! is_null( $exception ) ) { - /* translators: %s: exception message */ - $log_message = sprintf( __( 'There was a failure fetching this action: %s', 'action-scheduler' ), $exception->getMessage() ); - } else { - $log_message = __( 'There was a failure fetching this action', 'action-scheduler' ); - } - - $this->log( $action_id, $log_message ); - } - - public function log_failed_schedule_next_instance( $action_id, Exception $exception ) { - /* translators: %s: exception message */ - $this->log( $action_id, sprintf( __( 'There was a failure scheduling the next instance of this action: %s', 'action-scheduler' ), $exception->getMessage() ) ); - } - - /** - * Bulk add cancel action log entries. - * - * Implemented here for backward compatibility. Should be implemented in parent loggers - * for more performant bulk logging. - * - * @param array $action_ids List of action ID. - */ - public function bulk_log_cancel_actions( $action_ids ) { - if ( empty( $action_ids ) ) { - return; - } - - foreach ( $action_ids as $action_id ) { - $this->log_canceled_action( $action_id ); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Store.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Store.php deleted file mode 100644 index 252b701..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Store.php +++ /dev/null @@ -1,345 +0,0 @@ -', '>=', '<', '<=', '=') ) ) { - return $comparison_operator; - } - return '='; - } - - /** - * Get the time MySQL formated date/time string for an action's (next) scheduled date. - * - * @param ActionScheduler_Action $action - * @param DateTime $scheduled_date (optional) - * @return string - */ - protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) { - $next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date; - if ( ! $next ) { - return '0000-00-00 00:00:00'; - } - $next->setTimezone( new DateTimeZone( 'UTC' ) ); - - return $next->format( 'Y-m-d H:i:s' ); - } - - /** - * Get the time MySQL formated date/time string for an action's (next) scheduled date. - * - * @param ActionScheduler_Action $action - * @param DateTime $scheduled_date (optional) - * @return string - */ - protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) { - $next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date; - if ( ! $next ) { - return '0000-00-00 00:00:00'; - } - - ActionScheduler_TimezoneHelper::set_local_timezone( $next ); - return $next->format( 'Y-m-d H:i:s' ); - } - - /** - * Validate that we could decode action arguments. - * - * @param mixed $args The decoded arguments. - * @param int $action_id The action ID. - * - * @throws ActionScheduler_InvalidActionException When the decoded arguments are invalid. - */ - protected function validate_args( $args, $action_id ) { - // Ensure we have an array of args. - if ( ! is_array( $args ) ) { - throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id ); - } - - // Validate JSON decoding if possible. - if ( function_exists( 'json_last_error' ) && JSON_ERROR_NONE !== json_last_error() ) { - throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id, $args ); - } - } - - /** - * Validate a ActionScheduler_Schedule object. - * - * @param mixed $schedule The unserialized ActionScheduler_Schedule object. - * @param int $action_id The action ID. - * - * @throws ActionScheduler_InvalidActionException When the schedule is invalid. - */ - protected function validate_schedule( $schedule, $action_id ) { - if ( empty( $schedule ) || ! is_a( $schedule, 'ActionScheduler_Schedule' ) ) { - throw ActionScheduler_InvalidActionException::from_schedule( $action_id, $schedule ); - } - } - - /** - * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4. - * - * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However, - * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn - * developers of this impending requirement. - * - * @param ActionScheduler_Action $action - */ - protected function validate_action( ActionScheduler_Action $action ) { - if ( strlen( json_encode( $action->get_args() ) ) > self::$max_index_length ) { - throw new InvalidArgumentException( __( 'ActionScheduler_Action::$args too long. To ensure the args column can be indexed, action args should not be more than 191 characters when encoded as JSON.', 'action-scheduler' ) ); - } - } - - /** - * Cancel pending actions by hook. - * - * @since 3.0.0 - * - * @param string $hook Hook name. - * - * @return void - */ - public function cancel_actions_by_hook( $hook ) { - $action_ids = true; - while ( ! empty( $action_ids ) ) { - $action_ids = $this->query_actions( - array( - 'hook' => $hook, - 'status' => self::STATUS_PENDING, - 'per_page' => 1000, - ) - ); - - $this->bulk_cancel_actions( $action_ids ); - } - } - - /** - * Cancel pending actions by group. - * - * @since 3.0.0 - * - * @param string $group Group slug. - * - * @return void - */ - public function cancel_actions_by_group( $group ) { - $action_ids = true; - while ( ! empty( $action_ids ) ) { - $action_ids = $this->query_actions( - array( - 'group' => $group, - 'status' => self::STATUS_PENDING, - 'per_page' => 1000, - ) - ); - - $this->bulk_cancel_actions( $action_ids ); - } - } - - /** - * Cancel a set of action IDs. - * - * @since 3.0.0 - * - * @param array $action_ids List of action IDs. - * - * @return void - */ - private function bulk_cancel_actions( $action_ids ) { - foreach ( $action_ids as $action_id ) { - $this->cancel_action( $action_id ); - } - - do_action( 'action_scheduler_bulk_cancel_actions', $action_ids ); - } - - /** - * @return array - */ - public function get_status_labels() { - return array( - self::STATUS_COMPLETE => __( 'Complete', 'action-scheduler' ), - self::STATUS_PENDING => __( 'Pending', 'action-scheduler' ), - self::STATUS_RUNNING => __( 'In-progress', 'action-scheduler' ), - self::STATUS_FAILED => __( 'Failed', 'action-scheduler' ), - self::STATUS_CANCELED => __( 'Canceled', 'action-scheduler' ), - ); - } - - /** - * Check if there are any pending scheduled actions due to run. - * - * @param ActionScheduler_Action $action - * @param DateTime $scheduled_date (optional) - * @return string - */ - public function has_pending_actions_due() { - $pending_actions = $this->query_actions( array( - 'date' => as_get_datetime_object(), - 'status' => ActionScheduler_Store::STATUS_PENDING, - ) ); - - return ! empty( $pending_actions ); - } - - /** - * Callable initialization function optionally overridden in derived classes. - */ - public function init() {} - - /** - * Callable function to mark an action as migrated optionally overridden in derived classes. - */ - public function mark_migrated( $action_id ) {} - - /** - * @return ActionScheduler_Store - */ - public static function instance() { - if ( empty( self::$store ) ) { - $class = apply_filters( 'action_scheduler_store_class', self::DEFAULT_CLASS ); - self::$store = new $class(); - } - return self::$store; - } -} diff --git a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php b/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php deleted file mode 100644 index fd01449..0000000 --- a/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php +++ /dev/null @@ -1,152 +0,0 @@ -format( 'U' ) ); - } - - if ( get_option( 'timezone_string' ) ) { - $date->setTimezone( new DateTimeZone( self::get_local_timezone_string() ) ); - } else { - $date->setUtcOffset( self::get_local_timezone_offset() ); - } - - return $date; - } - - /** - * Helper to retrieve the timezone string for a site until a WP core method exists - * (see https://core.trac.wordpress.org/ticket/24730). - * - * Adapted from wc_timezone_string() and https://secure.php.net/manual/en/function.timezone-name-from-abbr.php#89155. - * - * If no timezone string is set, and its not possible to match the UTC offset set for the site to a timezone - * string, then an empty string will be returned, and the UTC offset should be used to set a DateTime's - * timezone. - * - * @since 2.1.0 - * @return string PHP timezone string for the site or empty if no timezone string is available. - */ - protected static function get_local_timezone_string( $reset = false ) { - // If site timezone string exists, return it. - $timezone = get_option( 'timezone_string' ); - if ( $timezone ) { - return $timezone; - } - - // Get UTC offset, if it isn't set then return UTC. - $utc_offset = intval( get_option( 'gmt_offset', 0 ) ); - if ( 0 === $utc_offset ) { - return 'UTC'; - } - - // Adjust UTC offset from hours to seconds. - $utc_offset *= 3600; - - // Attempt to guess the timezone string from the UTC offset. - $timezone = timezone_name_from_abbr( '', $utc_offset ); - if ( $timezone ) { - return $timezone; - } - - // Last try, guess timezone string manually. - foreach ( timezone_abbreviations_list() as $abbr ) { - foreach ( $abbr as $city ) { - if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { - return $city['timezone_id']; - } - } - } - - // No timezone string - return ''; - } - - /** - * Get timezone offset in seconds. - * - * @since 2.1.0 - * @return float - */ - protected static function get_local_timezone_offset() { - $timezone = get_option( 'timezone_string' ); - - if ( $timezone ) { - $timezone_object = new DateTimeZone( $timezone ); - return $timezone_object->getOffset( new DateTime( 'now' ) ); - } else { - return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS; - } - } - - /** - * @deprecated 2.1.0 - */ - public static function get_local_timezone( $reset = FALSE ) { - _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' ); - if ( $reset ) { - self::$local_timezone = NULL; - } - if ( !isset(self::$local_timezone) ) { - $tzstring = get_option('timezone_string'); - - if ( empty($tzstring) ) { - $gmt_offset = get_option('gmt_offset'); - if ( $gmt_offset == 0 ) { - $tzstring = 'UTC'; - } else { - $gmt_offset *= HOUR_IN_SECONDS; - $tzstring = timezone_name_from_abbr( '', $gmt_offset, 1 ); - - // If there's no timezone string, try again with no DST. - if ( false === $tzstring ) { - $tzstring = timezone_name_from_abbr( '', $gmt_offset, 0 ); - } - - // Try mapping to the first abbreviation we can find. - if ( false === $tzstring ) { - $is_dst = date( 'I' ); - foreach ( timezone_abbreviations_list() as $abbr ) { - foreach ( $abbr as $city ) { - if ( $city['dst'] == $is_dst && $city['offset'] == $gmt_offset ) { - // If there's no valid timezone ID, keep looking. - if ( null === $city['timezone_id'] ) { - continue; - } - - $tzstring = $city['timezone_id']; - break 2; - } - } - } - } - - // If we still have no valid string, then fall back to UTC. - if ( false === $tzstring ) { - $tzstring = 'UTC'; - } - } - } - - self::$local_timezone = new DateTimeZone($tzstring); - } - return self::$local_timezone; - } -} diff --git a/includes/libraries/action-scheduler/classes/actions/ActionScheduler_Action.php b/includes/libraries/action-scheduler/classes/actions/ActionScheduler_Action.php deleted file mode 100644 index 6258ba1..0000000 --- a/includes/libraries/action-scheduler/classes/actions/ActionScheduler_Action.php +++ /dev/null @@ -1,75 +0,0 @@ -set_hook($hook); - $this->set_schedule($schedule); - $this->set_args($args); - $this->set_group($group); - } - - public function execute() { - return do_action_ref_array($this->get_hook(), $this->get_args()); - } - - /** - * @param string $hook - */ - protected function set_hook( $hook ) { - $this->hook = $hook; - } - - public function get_hook() { - return $this->hook; - } - - protected function set_schedule( ActionScheduler_Schedule $schedule ) { - $this->schedule = $schedule; - } - - /** - * @return ActionScheduler_Schedule - */ - public function get_schedule() { - return $this->schedule; - } - - protected function set_args( array $args ) { - $this->args = $args; - } - - public function get_args() { - return $this->args; - } - - /** - * @param string $group - */ - protected function set_group( $group ) { - $this->group = $group; - } - - /** - * @return string - */ - public function get_group() { - return $this->group; - } - - /** - * @return bool If the action has been finished - */ - public function is_finished() { - return FALSE; - } -} diff --git a/includes/libraries/action-scheduler/classes/actions/ActionScheduler_CanceledAction.php b/includes/libraries/action-scheduler/classes/actions/ActionScheduler_CanceledAction.php deleted file mode 100644 index 8bbc5d1..0000000 --- a/includes/libraries/action-scheduler/classes/actions/ActionScheduler_CanceledAction.php +++ /dev/null @@ -1,23 +0,0 @@ -set_schedule( new ActionScheduler_NullSchedule() ); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/actions/ActionScheduler_FinishedAction.php b/includes/libraries/action-scheduler/classes/actions/ActionScheduler_FinishedAction.php deleted file mode 100644 index b23a56c..0000000 --- a/includes/libraries/action-scheduler/classes/actions/ActionScheduler_FinishedAction.php +++ /dev/null @@ -1,16 +0,0 @@ -set_schedule( new ActionScheduler_NullSchedule() ); - } - - public function execute() { - // don't execute - } -} - \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php deleted file mode 100644 index d21e869..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php +++ /dev/null @@ -1,146 +0,0 @@ -format( 'Y-m-d H:i:s' ); - ActionScheduler_TimezoneHelper::set_local_timezone( $date ); - $date_local = $date->format( 'Y-m-d H:i:s' ); - - /** @var \wpdb $wpdb */ - global $wpdb; - $wpdb->insert( $wpdb->actionscheduler_logs, [ - 'action_id' => $action_id, - 'message' => $message, - 'log_date_gmt' => $date_gmt, - 'log_date_local' => $date_local, - ], [ '%d', '%s', '%s', '%s' ] ); - - return $wpdb->insert_id; - } - - /** - * Retrieve an action log entry. - * - * @param int $entry_id Log entry ID. - * - * @return ActionScheduler_LogEntry - */ - public function get_entry( $entry_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) ); - - return $this->create_entry_from_db_record( $entry ); - } - - /** - * Create an action log entry from a database record. - * - * @param object $record Log entry database record object. - * - * @return ActionScheduler_LogEntry - */ - private function create_entry_from_db_record( $record ) { - if ( empty( $record ) ) { - return new ActionScheduler_NullLogEntry(); - } - - $date = as_get_datetime_object( $record->log_date_gmt ); - - return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date ); - } - - /** - * Retrieve the an action's log entries from the database. - * - * @param int $action_id Action ID. - * - * @return ActionScheduler_LogEntry[] - */ - public function get_logs( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) ); - - return array_map( [ $this, 'create_entry_from_db_record' ], $records ); - } - - /** - * Initialize the data store. - * - * @codeCoverageIgnore - */ - public function init() { - - $table_maker = new ActionScheduler_LoggerSchema(); - $table_maker->register_tables(); - - parent::init(); - - add_action( 'action_scheduler_deleted_action', [ $this, 'clear_deleted_action_logs' ], 10, 1 ); - } - - /** - * Delete the action logs for an action. - * - * @param int $action_id Action ID. - */ - public function clear_deleted_action_logs( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] ); - } - - /** - * Bulk add cancel action log entries. - * - * @param array $action_ids List of action ID. - */ - public function bulk_log_cancel_actions( $action_ids ) { - if ( empty( $action_ids ) ) { - return; - } - - /** @var \wpdb $wpdb */ - global $wpdb; - $date = as_get_datetime_object(); - $date_gmt = $date->format( 'Y-m-d H:i:s' ); - ActionScheduler_TimezoneHelper::set_local_timezone( $date ); - $date_local = $date->format( 'Y-m-d H:i:s' ); - $message = __( 'action canceled', 'action-scheduler' ); - $format = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')'; - $sql_query = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES "; - $value_rows = []; - - foreach ( $action_ids as $action_id ) { - $value_rows[] = $wpdb->prepare( $format, $action_id ); - } - $sql_query .= implode( ',', $value_rows ); - - $wpdb->query( $sql_query ); - } -} diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php deleted file mode 100644 index 2fd1ae7..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php +++ /dev/null @@ -1,803 +0,0 @@ -register_tables(); - } - - /** - * Save an action. - * - * @param ActionScheduler_Action $action Action object. - * @param DateTime $date Optional schedule date. Default null. - * - * @return int Action ID. - */ - public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) { - try { - - $this->validate_action( $action ); - - /** @var \wpdb $wpdb */ - global $wpdb; - $data = [ - 'hook' => $action->get_hook(), - 'status' => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ), - 'scheduled_date_gmt' => $this->get_scheduled_date_string( $action, $date ), - 'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ), - 'args' => json_encode( $action->get_args() ), - 'schedule' => serialize( $action->get_schedule() ), - 'group_id' => $this->get_group_id( $action->get_group() ), - ]; - $wpdb->insert( $wpdb->actionscheduler_actions, $data ); - $action_id = $wpdb->insert_id; - - if ( is_wp_error( $action_id ) ) { - throw new RuntimeException( $action_id->get_error_message() ); - } - elseif ( empty( $action_id ) ) { - throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) ); - } - - do_action( 'action_scheduler_stored_action', $action_id ); - - return $action_id; - } catch ( \Exception $e ) { - /* translators: %s: error message */ - throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 ); - } - } - - /** - * Get a group's ID based on its name/slug. - * - * @param string $slug The string name of a group. - * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group. - * - * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created. - */ - protected function get_group_id( $slug, $create_if_not_exists = true ) { - if ( empty( $slug ) ) { - return 0; - } - /** @var \wpdb $wpdb */ - global $wpdb; - $group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) ); - if ( empty( $group_id ) && $create_if_not_exists ) { - $group_id = $this->create_group( $slug ); - } - - return $group_id; - } - - /** - * Create an action group. - * - * @param string $slug Group slug. - * - * @return int Group ID. - */ - protected function create_group( $slug ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $wpdb->insert( $wpdb->actionscheduler_groups, [ 'slug' => $slug ] ); - - return (int) $wpdb->insert_id; - } - - /** - * Retrieve an action. - * - * @param int $action_id Action ID. - * - * @return ActionScheduler_Action - */ - public function fetch_action( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $data = $wpdb->get_row( $wpdb->prepare( - "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d", - $action_id - ) ); - - if ( empty( $data ) ) { - return $this->get_null_action(); - } - - try { - $action = $this->make_action_from_db_record( $data ); - } catch ( ActionScheduler_InvalidActionException $exception ) { - do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception ); - return $this->get_null_action(); - } - - return $action; - } - - /** - * Create a null action. - * - * @return ActionScheduler_NullAction - */ - protected function get_null_action() { - return new ActionScheduler_NullAction(); - } - - /** - * Create an action from a database record. - * - * @param object $data Action database record. - * - * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction - */ - protected function make_action_from_db_record( $data ) { - - $hook = $data->hook; - $args = json_decode( $data->args, true ); - $schedule = unserialize( $data->schedule ); - - $this->validate_args( $args, $data->action_id ); - $this->validate_schedule( $schedule, $data->action_id ); - - if ( empty( $schedule ) ) { - $schedule = new ActionScheduler_NullSchedule(); - } - $group = $data->group ? $data->group : ''; - - return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group ); - } - - /** - * Find an action. - * - * @param string $hook Action hook. - * @param array $params Parameters of the action to find. - * - * @return string|null ID of the next action matching the criteria or NULL if not found. - */ - public function find_action( $hook, $params = [] ) { - $params = wp_parse_args( $params, [ - 'args' => null, - 'status' => self::STATUS_PENDING, - 'group' => '', - ] ); - - /** @var wpdb $wpdb */ - global $wpdb; - $query = "SELECT a.action_id FROM {$wpdb->actionscheduler_actions} a"; - $args = []; - if ( ! empty( $params[ 'group' ] ) ) { - $query .= " INNER JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id AND g.slug=%s"; - $args[] = $params[ 'group' ]; - } - $query .= " WHERE a.hook=%s"; - $args[] = $hook; - if ( ! is_null( $params[ 'args' ] ) ) { - $query .= " AND a.args=%s"; - $args[] = json_encode( $params[ 'args' ] ); - } - - $order = 'ASC'; - if ( ! empty( $params[ 'status' ] ) ) { - $query .= " AND a.status=%s"; - $args[] = $params[ 'status' ]; - - if ( self::STATUS_PENDING == $params[ 'status' ] ) { - $order = 'ASC'; // Find the next action that matches. - } else { - $order = 'DESC'; // Find the most recent action that matches. - } - } - - $query .= " ORDER BY scheduled_date_gmt $order LIMIT 1"; - - $query = $wpdb->prepare( $query, $args ); - - $id = $wpdb->get_var( $query ); - - return $id; - } - - /** - * Returns the SQL statement to query (or count) actions. - * - * @param array $query Filtering options. - * @param string $select_or_count Whether the SQL should select and return the IDs or just the row count. - * - * @return string SQL statement already properly escaped. - */ - protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) { - - if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) { - throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) ); - } - - $query = wp_parse_args( $query, [ - 'hook' => '', - 'args' => null, - 'date' => null, - 'date_compare' => '<=', - 'modified' => null, - 'modified_compare' => '<=', - 'group' => '', - 'status' => '', - 'claimed' => null, - 'per_page' => 5, - 'offset' => 0, - 'orderby' => 'date', - 'order' => 'ASC', - ] ); - - /** @var \wpdb $wpdb */ - global $wpdb; - $sql = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id'; - $sql .= " FROM {$wpdb->actionscheduler_actions} a"; - $sql_params = []; - - if ( ! empty( $query[ 'group' ] ) || 'group' === $query[ 'orderby' ] ) { - $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id"; - } - - $sql .= " WHERE 1=1"; - - if ( ! empty( $query[ 'group' ] ) ) { - $sql .= " AND g.slug=%s"; - $sql_params[] = $query[ 'group' ]; - } - - if ( $query[ 'hook' ] ) { - $sql .= " AND a.hook=%s"; - $sql_params[] = $query[ 'hook' ]; - } - if ( ! is_null( $query[ 'args' ] ) ) { - $sql .= " AND a.args=%s"; - $sql_params[] = json_encode( $query[ 'args' ] ); - } - - if ( $query[ 'status' ] ) { - $sql .= " AND a.status=%s"; - $sql_params[] = $query[ 'status' ]; - } - - if ( $query[ 'date' ] instanceof \DateTime ) { - $date = clone $query[ 'date' ]; - $date->setTimezone( new \DateTimeZone( 'UTC' ) ); - $date_string = $date->format( 'Y-m-d H:i:s' ); - $comparator = $this->validate_sql_comparator( $query[ 'date_compare' ] ); - $sql .= " AND a.scheduled_date_gmt $comparator %s"; - $sql_params[] = $date_string; - } - - if ( $query[ 'modified' ] instanceof \DateTime ) { - $modified = clone $query[ 'modified' ]; - $modified->setTimezone( new \DateTimeZone( 'UTC' ) ); - $date_string = $modified->format( 'Y-m-d H:i:s' ); - $comparator = $this->validate_sql_comparator( $query[ 'modified_compare' ] ); - $sql .= " AND a.last_attempt_gmt $comparator %s"; - $sql_params[] = $date_string; - } - - if ( $query[ 'claimed' ] === true ) { - $sql .= " AND a.claim_id != 0"; - } elseif ( $query[ 'claimed' ] === false ) { - $sql .= " AND a.claim_id = 0"; - } elseif ( ! is_null( $query[ 'claimed' ] ) ) { - $sql .= " AND a.claim_id = %d"; - $sql_params[] = $query[ 'claimed' ]; - } - - if ( ! empty( $query['search'] ) ) { - $sql .= " AND (a.hook LIKE %s OR a.args LIKE %s"; - for( $i = 0; $i < 2; $i++ ) { - $sql_params[] = sprintf( '%%%s%%', $query['search'] ); - } - - $search_claim_id = (int) $query['search']; - if ( $search_claim_id ) { - $sql .= ' OR a.claim_id = %d'; - $sql_params[] = $search_claim_id; - } - - $sql .= ')'; - } - - if ( 'select' === $select_or_count ) { - switch ( $query['orderby'] ) { - case 'hook': - $orderby = 'a.hook'; - break; - case 'group': - $orderby = 'g.slug'; - break; - case 'modified': - $orderby = 'a.last_attempt_gmt'; - break; - case 'date': - default: - $orderby = 'a.scheduled_date_gmt'; - break; - } - if ( strtoupper( $query[ 'order' ] ) == 'ASC' ) { - $order = 'ASC'; - } else { - $order = 'DESC'; - } - $sql .= " ORDER BY $orderby $order"; - if ( $query[ 'per_page' ] > 0 ) { - $sql .= " LIMIT %d, %d"; - $sql_params[] = $query[ 'offset' ]; - $sql_params[] = $query[ 'per_page' ]; - } - } - - if ( ! empty( $sql_params ) ) { - $sql = $wpdb->prepare( $sql, $sql_params ); - } - - return $sql; - } - - /** - * Query for action count of list of action IDs. - * - * @param array $query Query parameters. - * @param string $query_type Whether to select or count the results. Default, select. - * - * @return null|string|array The IDs of actions matching the query - */ - public function query_actions( $query = [], $query_type = 'select' ) { - /** @var wpdb $wpdb */ - global $wpdb; - - $sql = $this->get_query_actions_sql( $query, $query_type ); - - return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); - } - - /** - * Get a count of all actions in the store, grouped by status. - * - * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status. - */ - public function action_counts() { - global $wpdb; - - $sql = "SELECT a.status, count(a.status) as 'count'"; - $sql .= " FROM {$wpdb->actionscheduler_actions} a"; - $sql .= " GROUP BY a.status"; - - $actions_count_by_status = array(); - $action_stati_and_labels = $this->get_status_labels(); - - foreach ( $wpdb->get_results( $sql ) as $action_data ) { - // Ignore any actions with invalid status - if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) { - $actions_count_by_status[ $action_data->status ] = $action_data->count; - } - } - - return $actions_count_by_status; - } - - /** - * Cancel an action. - * - * @param int $action_id Action ID. - * - * @return void - */ - public function cancel_action( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - $updated = $wpdb->update( - $wpdb->actionscheduler_actions, - [ 'status' => self::STATUS_CANCELED ], - [ 'action_id' => $action_id ], - [ '%s' ], - [ '%d' ] - ); - if ( empty( $updated ) ) { - /* translators: %s: action ID */ - throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); - } - do_action( 'action_scheduler_canceled_action', $action_id ); - } - - /** - * Cancel pending actions by hook. - * - * @since 3.0.0 - * - * @param string $hook Hook name. - * - * @return void - */ - public function cancel_actions_by_hook( $hook ) { - $this->bulk_cancel_actions( [ 'hook' => $hook ] ); - } - - /** - * Cancel pending actions by group. - * - * @param string $group Group slug. - * - * @return void - */ - public function cancel_actions_by_group( $group ) { - $this->bulk_cancel_actions( [ 'group' => $group ] ); - } - - /** - * Bulk cancel actions. - * - * @since 3.0.0 - * - * @param array $query_args Query parameters. - */ - protected function bulk_cancel_actions( $query_args ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - if ( ! is_array( $query_args ) ) { - return; - } - - // Don't cancel actions that are already canceled. - if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) { - return; - } - - $action_ids = true; - $query_args = wp_parse_args( - $query_args, - [ - 'per_page' => 1000, - 'status' => self::STATUS_PENDING, - ] - ); - - while ( $action_ids ) { - $action_ids = $this->query_actions( $query_args ); - if ( empty( $action_ids ) ) { - break; - } - - $format = array_fill( 0, count( $action_ids ), '%d' ); - $query_in = '(' . implode( ',', $format ) . ')'; - $parameters = $action_ids; - array_unshift( $parameters, self::STATUS_CANCELED ); - - $wpdb->query( - $wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok. - "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", - $parameters - ) - ); - - do_action( 'action_scheduler_bulk_cancel_actions', $action_ids ); - } - } - - /** - * Delete an action. - * - * @param int $action_id Action ID. - */ - public function delete_action( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, [ 'action_id' => $action_id ], [ '%d' ] ); - if ( empty( $deleted ) ) { - throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); - } - do_action( 'action_scheduler_deleted_action', $action_id ); - } - - /** - * Get the schedule date for an action. - * - * @param string $action_id Action ID. - * - * @throws \InvalidArgumentException - * @return \DateTime The local date the action is scheduled to run, or the date that it ran. - */ - public function get_date( $action_id ) { - $date = $this->get_date_gmt( $action_id ); - ActionScheduler_TimezoneHelper::set_local_timezone( $date ); - return $date; - } - - /** - * Get the GMT schedule date for an action. - * - * @param int $action_id Action ID. - * - * @throws \InvalidArgumentException - * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran. - */ - protected function get_date_gmt( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) ); - if ( empty( $record ) ) { - throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); - } - if ( $record->status == self::STATUS_PENDING ) { - return as_get_datetime_object( $record->scheduled_date_gmt ); - } else { - return as_get_datetime_object( $record->last_attempt_gmt ); - } - } - - /** - * Stake a claim on actions. - * - * @param int $max_actions Maximum number of action to include in claim. - * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now. - * - * @return ActionScheduler_ActionClaim - */ - public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) { - $claim_id = $this->generate_claim_id(); - $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group ); - $action_ids = $this->find_actions_by_claim_id( $claim_id ); - - return new ActionScheduler_ActionClaim( $claim_id, $action_ids ); - } - - /** - * Generate a new action claim. - * - * @return int Claim ID. - */ - protected function generate_claim_id() { - /** @var \wpdb $wpdb */ - global $wpdb; - $now = as_get_datetime_object(); - $wpdb->insert( $wpdb->actionscheduler_claims, [ 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ] ); - - return $wpdb->insert_id; - } - - /** - * Mark actions claimed. - * - * @param string $claim_id Claim Id. - * @param int $limit Number of action to include in claim. - * @param \DateTime $before_date Should use UTC timezone. - * - * @return int The number of actions that were claimed. - * @throws \RuntimeException - */ - protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - $now = as_get_datetime_object(); - $date = is_null( $before_date ) ? $now : clone $before_date; - - // can't use $wpdb->update() because of the <= condition - $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s"; - $params = array( - $claim_id, - $now->format( 'Y-m-d H:i:s' ), - current_time( 'mysql' ), - ); - - $where = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s"; - $params[] = $date->format( 'Y-m-d H:i:s' ); - $params[] = self::STATUS_PENDING; - - if ( ! empty( $hooks ) ) { - $placeholders = array_fill( 0, count( $hooks ), '%s' ); - $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')'; - $params = array_merge( $params, array_values( $hooks ) ); - } - - if ( ! empty( $group ) ) { - - $group_id = $this->get_group_id( $group, false ); - - // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour - if ( empty( $group_id ) ) { - /* translators: %s: group name */ - throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) ); - } - - $where .= ' AND group_id = %d'; - $params[] = $group_id; - } - - $order = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d"; - $params[] = $limit; - - $sql = $wpdb->prepare( "{$update} {$where} {$order}", $params ); - - $rows_affected = $wpdb->query( $sql ); - if ( $rows_affected === false ) { - throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); - } - - return (int) $rows_affected; - } - - /** - * Get the number of active claims. - * - * @return int - */ - public function get_claim_count() { - global $wpdb; - - $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)"; - $sql = $wpdb->prepare( $sql, [ self::STATUS_PENDING, self::STATUS_RUNNING ] ); - - return (int) $wpdb->get_var( $sql ); - } - - /** - * Return an action's claim ID, as stored in the claim_id column. - * - * @param string $action_id Action ID. - * @return mixed - */ - public function get_claim_id( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d"; - $sql = $wpdb->prepare( $sql, $action_id ); - - return (int) $wpdb->get_var( $sql ); - } - - /** - * Retrieve the action IDs of action in a claim. - * - * @param string $claim_id Claim ID. - * - * @return int[] - */ - public function find_actions_by_claim_id( $claim_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - $sql = "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id=%d"; - $sql = $wpdb->prepare( $sql, $claim_id ); - - $action_ids = $wpdb->get_col( $sql ); - - return array_map( 'intval', $action_ids ); - } - - /** - * Release actions from a claim and delete the claim. - * - * @param ActionScheduler_ActionClaim $claim Claim object. - */ - public function release_claim( ActionScheduler_ActionClaim $claim ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $wpdb->update( $wpdb->actionscheduler_actions, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] ); - $wpdb->delete( $wpdb->actionscheduler_claims, [ 'claim_id' => $claim->get_id() ], [ '%d' ] ); - } - - /** - * Remove the claim from an action. - * - * @param int $action_id Action ID. - * - * @return void - */ - public function unclaim_action( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $wpdb->update( - $wpdb->actionscheduler_actions, - [ 'claim_id' => 0 ], - [ 'action_id' => $action_id ], - [ '%s' ], - [ '%d' ] - ); - } - - /** - * Mark an action as failed. - * - * @param int $action_id Action ID. - */ - public function mark_failure( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $updated = $wpdb->update( - $wpdb->actionscheduler_actions, - [ 'status' => self::STATUS_FAILED ], - [ 'action_id' => $action_id ], - [ '%s' ], - [ '%d' ] - ); - if ( empty( $updated ) ) { - throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); - } - } - - /** - * Add execution message to action log. - * - * @param int $action_id Action ID. - * - * @return void - */ - public function log_execution( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - - $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d"; - $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); - $wpdb->query( $sql ); - } - - /** - * Mark an action as complete. - * - * @param int $action_id Action ID. - * - * @return void - */ - public function mark_complete( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $updated = $wpdb->update( - $wpdb->actionscheduler_actions, - [ - 'status' => self::STATUS_COMPLETE, - 'last_attempt_gmt' => current_time( 'mysql', true ), - 'last_attempt_local' => current_time( 'mysql' ), - ], - [ 'action_id' => $action_id ], - [ '%s' ], - [ '%d' ] - ); - if ( empty( $updated ) ) { - throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); - } - } - - /** - * Get an action's status. - * - * @param int $action_id Action ID. - * - * @return string - */ - public function get_status( $action_id ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d"; - $sql = $wpdb->prepare( $sql, $action_id ); - $status = $wpdb->get_var( $sql ); - - if ( $status === null ) { - throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) ); - } elseif ( empty( $status ) ) { - throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) ); - } else { - return $status; - } - } -} diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php deleted file mode 100644 index bf68af3..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php +++ /dev/null @@ -1,380 +0,0 @@ -demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 ); - if ( empty( $config ) ) { - $config = Controller::instance()->get_migration_config_object(); - } - $this->primary_store = $config->get_destination_store(); - $this->secondary_store = $config->get_source_store(); - $this->migration_runner = new Runner( $config ); - } - - /** - * Initialize the table data store tables. - * - * @codeCoverageIgnore - */ - public function init() { - add_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10, 2 ); - $this->primary_store->init(); - $this->secondary_store->init(); - remove_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10 ); - } - - /** - * When the actions table is created, set its autoincrement - * value to be one higher than the posts table to ensure that - * there are no ID collisions. - * - * @param string $table_name - * @param string $table_suffix - * - * @return void - * @codeCoverageIgnore - */ - public function set_autoincrement( $table_name, $table_suffix ) { - if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) { - if ( empty( $this->demarkation_id ) ) { - $this->demarkation_id = $this->set_demarkation_id(); - } - /** @var \wpdb $wpdb */ - global $wpdb; - $wpdb->insert( - $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, - [ - 'action_id' => $this->demarkation_id, - 'hook' => '', - 'status' => '', - ] - ); - $wpdb->delete( - $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, - [ 'action_id' => $this->demarkation_id ] - ); - } - } - - /** - * Store the demarkation id in WP options. - * - * @param int $id The ID to set as the demarkation point between the two stores - * Leave null to use the next ID from the WP posts table. - * - * @return int The new ID. - * - * @codeCoverageIgnore - */ - private function set_demarkation_id( $id = null ) { - if ( empty( $id ) ) { - /** @var \wpdb $wpdb */ - global $wpdb; - $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" ); - $id ++; - } - update_option( self::DEMARKATION_OPTION, $id ); - - return $id; - } - - /** - * Find the first matching action from the secondary store. - * If it exists, migrate it to the primary store immediately. - * After it migrates, the secondary store will logically contain - * the next matching action, so return the result thence. - * - * @param string $hook - * @param array $params - * - * @return string - */ - public function find_action( $hook, $params = [] ) { - $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params ); - if ( ! empty( $found_unmigrated_action ) ) { - $this->migrate( [ $found_unmigrated_action ] ); - } - - return $this->primary_store->find_action( $hook, $params ); - } - - /** - * Find actions matching the query in the secondary source first. - * If any are found, migrate them immediately. Then the secondary - * store will contain the canonical results. - * - * @param array $query - * @param string $query_type Whether to select or count the results. Default, select. - * - * @return int[] - */ - public function query_actions( $query = [], $query_type = 'select' ) { - $found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' ); - if ( ! empty( $found_unmigrated_actions ) ) { - $this->migrate( $found_unmigrated_actions ); - } - - return $this->primary_store->query_actions( $query, $query_type ); - } - - /** - * Get a count of all actions in the store, grouped by status - * - * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status. - */ - public function action_counts() { - $unmigrated_actions_count = $this->secondary_store->action_counts(); - $migrated_actions_count = $this->primary_store->action_counts(); - $actions_count_by_status = array(); - - foreach ( $this->get_status_labels() as $status_key => $status_label ) { - - $count = 0; - - if ( isset( $unmigrated_actions_count[ $status_key ] ) ) { - $count += $unmigrated_actions_count[ $status_key ]; - } - - if ( isset( $migrated_actions_count[ $status_key ] ) ) { - $count += $migrated_actions_count[ $status_key ]; - } - - $actions_count_by_status[ $status_key ] = $count; - } - - $actions_count_by_status = array_filter( $actions_count_by_status ); - - return $actions_count_by_status; - } - - /** - * If any actions would have been claimed by the secondary store, - * migrate them immediately, then ask the primary store for the - * canonical claim. - * - * @param int $max_actions - * @param DateTime|null $before_date - * - * @return ActionScheduler_ActionClaim - */ - public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { - $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); - - $claimed_actions = $claim->get_actions(); - if ( ! empty( $claimed_actions ) ) { - $this->migrate( $claimed_actions ); - } - - $this->secondary_store->release_claim( $claim ); - - return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); - } - - /** - * Migrate a list of actions to the table data store. - * - * @param array $action_ids List of action IDs. - */ - private function migrate( $action_ids ) { - $this->migration_runner->migrate_actions( $action_ids ); - } - - /** - * Save an action to the primary store. - * - * @param ActionScheduler_Action $action Action object to be saved. - * @param DateTime $date Optional. Schedule date. Default null. - */ - public function save_action( ActionScheduler_Action $action, DateTime $date = null ) { - return $this->primary_store->save_action( $action, $date ); - } - - /** - * Retrieve an existing action whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function fetch_action( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - return $this->secondary_store->fetch_action( $action_id ); - } else { - return $this->primary_store->fetch_action( $action_id ); - } - } - - /** - * Cancel an existing action whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function cancel_action( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - $this->secondary_store->cancel_action( $action_id ); - } else { - $this->primary_store->cancel_action( $action_id ); - } - } - - /** - * Delete an existing action whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function delete_action( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - $this->secondary_store->delete_action( $action_id ); - } else { - $this->primary_store->delete_action( $action_id ); - } - } - - /** - * Get the schedule date an existing action whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function get_date( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - return $this->secondary_store->get_date( $action_id ); - } else { - return $this->primary_store->get_date( $action_id ); - } - } - - /** - * Mark an existing action as failed whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function mark_failure( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - $this->secondary_store->mark_failure( $action_id ); - } else { - $this->primary_store->mark_failure( $action_id ); - } - } - - /** - * Log the execution of an existing action whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function log_execution( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - $this->secondary_store->log_execution( $action_id ); - } else { - $this->primary_store->log_execution( $action_id ); - } - } - - /** - * Mark an existing action complete whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function mark_complete( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - $this->secondary_store->mark_complete( $action_id ); - } else { - $this->primary_store->mark_complete( $action_id ); - } - } - - /** - * Get an existing action status whether migrated or not. - * - * @param int $action_id Action ID. - */ - public function get_status( $action_id ) { - if ( $action_id < $this->demarkation_id ) { - return $this->secondary_store->get_status( $action_id ); - } else { - return $this->primary_store->get_status( $action_id ); - } - } - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * - * All claim-related functions should operate solely - * on the primary store. - * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Get the claim count from the table data store. - */ - public function get_claim_count() { - return $this->primary_store->get_claim_count(); - } - - /** - * Retrieve the claim ID for an action from the table data store. - * - * @param int $action_id Action ID. - */ - public function get_claim_id( $action_id ) { - return $this->primary_store->get_claim_id( $action_id ); - } - - /** - * Release a claim in the table data store. - * - * @param ActionScheduler_ActionClaim $claim Claim object. - */ - public function release_claim( ActionScheduler_ActionClaim $claim ) { - $this->primary_store->release_claim( $claim ); - } - - /** - * Release claims on an action in the table data store. - * - * @param int $action_id Action ID. - */ - public function unclaim_action( $action_id ) { - $this->primary_store->unclaim_action( $action_id ); - } - - /** - * Retrieve a list of action IDs by claim. - * - * @param int $claim_id Claim ID. - */ - public function find_actions_by_claim_id( $claim_id ) { - return $this->primary_store->find_actions_by_claim_id( $claim_id ); - } -} diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php deleted file mode 100644 index 7215ddd..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php +++ /dev/null @@ -1,240 +0,0 @@ -create_wp_comment( $action_id, $message, $date ); - return $comment_id; - } - - protected function create_wp_comment( $action_id, $message, DateTime $date ) { - - $comment_date_gmt = $date->format('Y-m-d H:i:s'); - ActionScheduler_TimezoneHelper::set_local_timezone( $date ); - $comment_data = array( - 'comment_post_ID' => $action_id, - 'comment_date' => $date->format('Y-m-d H:i:s'), - 'comment_date_gmt' => $comment_date_gmt, - 'comment_author' => self::AGENT, - 'comment_content' => $message, - 'comment_agent' => self::AGENT, - 'comment_type' => self::TYPE, - ); - return wp_insert_comment($comment_data); - } - - /** - * @param string $entry_id - * - * @return ActionScheduler_LogEntry - */ - public function get_entry( $entry_id ) { - $comment = $this->get_comment( $entry_id ); - if ( empty($comment) || $comment->comment_type != self::TYPE ) { - return new ActionScheduler_NullLogEntry(); - } - - $date = as_get_datetime_object( $comment->comment_date_gmt ); - ActionScheduler_TimezoneHelper::set_local_timezone( $date ); - return new ActionScheduler_LogEntry( $comment->comment_post_ID, $comment->comment_content, $date ); - } - - /** - * @param string $action_id - * - * @return ActionScheduler_LogEntry[] - */ - public function get_logs( $action_id ) { - $status = 'all'; - if ( get_post_status($action_id) == 'trash' ) { - $status = 'post-trashed'; - } - $comments = get_comments(array( - 'post_id' => $action_id, - 'orderby' => 'comment_date_gmt', - 'order' => 'ASC', - 'type' => self::TYPE, - 'status' => $status, - )); - $logs = array(); - foreach ( $comments as $c ) { - $entry = $this->get_entry( $c ); - if ( !empty($entry) ) { - $logs[] = $entry; - } - } - return $logs; - } - - protected function get_comment( $comment_id ) { - return get_comment( $comment_id ); - } - - - - /** - * @param WP_Comment_Query $query - */ - public function filter_comment_queries( $query ) { - foreach ( array('ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID') as $key ) { - if ( !empty($query->query_vars[$key]) ) { - return; // don't slow down queries that wouldn't include action_log comments anyway - } - } - $query->query_vars['action_log_filter'] = TRUE; - add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 ); - } - - /** - * @param array $clauses - * @param WP_Comment_Query $query - * - * @return array - */ - public function filter_comment_query_clauses( $clauses, $query ) { - if ( !empty($query->query_vars['action_log_filter']) ) { - $clauses['where'] .= $this->get_where_clause(); - } - return $clauses; - } - - /** - * Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not - * the WP_Comment_Query class handled by @see self::filter_comment_queries(). - * - * @param string $where - * @param WP_Query $query - * - * @return string - */ - public function filter_comment_feed( $where, $query ) { - if ( is_comment_feed() ) { - $where .= $this->get_where_clause(); - } - return $where; - } - - /** - * Return a SQL clause to exclude Action Scheduler comments. - * - * @return string - */ - protected function get_where_clause() { - global $wpdb; - return sprintf( " AND {$wpdb->comments}.comment_type != '%s'", self::TYPE ); - } - - /** - * Remove action log entries from wp_count_comments() - * - * @param array $stats - * @param int $post_id - * - * @return object - */ - public function filter_comment_count( $stats, $post_id ) { - global $wpdb; - - if ( 0 === $post_id ) { - $stats = $this->get_comment_count(); - } - - return $stats; - } - - /** - * Retrieve the comment counts from our cache, or the database if the cached version isn't set. - * - * @return object - */ - protected function get_comment_count() { - global $wpdb; - - $stats = get_transient( 'as_comment_count' ); - - if ( ! $stats ) { - $stats = array(); - - $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A ); - - $total = 0; - $stats = array(); - $approved = array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' ); - - foreach ( (array) $count as $row ) { - // Don't count post-trashed toward totals - if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) { - $total += $row['num_comments']; - } - if ( isset( $approved[ $row['comment_approved'] ] ) ) { - $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments']; - } - } - - $stats['total_comments'] = $total; - $stats['all'] = $total; - - foreach ( $approved as $key ) { - if ( empty( $stats[ $key ] ) ) { - $stats[ $key ] = 0; - } - } - - $stats = (object) $stats; - set_transient( 'as_comment_count', $stats ); - } - - return $stats; - } - - /** - * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache - * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called. - */ - public function delete_comment_count_cache() { - delete_transient( 'as_comment_count' ); - } - - /** - * @codeCoverageIgnore - */ - public function init() { - add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 ); - add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 ); - - parent::init(); - - add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 ); - add_action( 'wp_count_comments', array( $this, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs - add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 ); - - // Delete comments count cache whenever there is a new comment or a comment status changes - add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) ); - add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) ); - } - - public function disable_comment_counting() { - wp_defer_comment_counting(true); - } - public function enable_comment_counting() { - wp_defer_comment_counting(false); - } - -} diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php deleted file mode 100644 index 807ec10..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php +++ /dev/null @@ -1,858 +0,0 @@ -validate_action( $action ); - $post_array = $this->create_post_array( $action, $scheduled_date ); - $post_id = $this->save_post_array( $post_array ); - $this->save_post_schedule( $post_id, $action->get_schedule() ); - $this->save_action_group( $post_id, $action->get_group() ); - do_action( 'action_scheduler_stored_action', $post_id ); - return $post_id; - } catch ( Exception $e ) { - throw new RuntimeException( sprintf( __('Error saving action: %s', 'action-scheduler'), $e->getMessage() ), 0 ); - } - } - - protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) { - $post = array( - 'post_type' => self::POST_TYPE, - 'post_title' => $action->get_hook(), - 'post_content' => json_encode($action->get_args()), - 'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ), - 'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ), - 'post_date' => $this->get_scheduled_date_string_local( $action, $scheduled_date ), - ); - return $post; - } - - protected function save_post_array( $post_array ) { - add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 ); - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); - - $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ); - - if ( $has_kses ) { - // Prevent KSES from corrupting JSON in post_content. - kses_remove_filters(); - } - - $post_id = wp_insert_post($post_array); - - if ( $has_kses ) { - kses_init_filters(); - } - - remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); - - if ( is_wp_error($post_id) || empty($post_id) ) { - throw new RuntimeException(__('Unable to save action.', 'action-scheduler')); - } - return $post_id; - } - - public function filter_insert_post_data( $postdata ) { - if ( $postdata['post_type'] == self::POST_TYPE ) { - $postdata['post_author'] = 0; - if ( $postdata['post_status'] == 'future' ) { - $postdata['post_status'] = 'publish'; - } - } - return $postdata; - } - - /** - * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug(). - * - * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish' - * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug() - * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing - * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a - * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a - * database containing thousands of related post_name values. - * - * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue. - * - * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This - * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a - * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an - * action's slug, being probably unique is good enough. - * - * For more backstory on this issue, see: - * - https://github.com/woocommerce/action-scheduler/issues/44 and - * - https://core.trac.wordpress.org/ticket/21112 - * - * @param string $override_slug Short-circuit return value. - * @param string $slug The desired slug (post_name). - * @param int $post_ID Post ID. - * @param string $post_status The post status. - * @param string $post_type Post type. - * @return string - */ - public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) { - if ( self::POST_TYPE == $post_type ) { - $override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false ); - } - return $override_slug; - } - - protected function save_post_schedule( $post_id, $schedule ) { - update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule ); - } - - protected function save_action_group( $post_id, $group ) { - if ( empty($group) ) { - wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, FALSE ); - } else { - wp_set_object_terms( $post_id, array($group), self::GROUP_TAXONOMY, FALSE ); - } - } - - public function fetch_action( $action_id ) { - $post = $this->get_post( $action_id ); - if ( empty($post) || $post->post_type != self::POST_TYPE ) { - return $this->get_null_action(); - } - - try { - $action = $this->make_action_from_post( $post ); - } catch ( ActionScheduler_InvalidActionException $exception ) { - do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception ); - return $this->get_null_action(); - } - - return $action; - } - - protected function get_post( $action_id ) { - if ( empty($action_id) ) { - return NULL; - } - return get_post($action_id); - } - - protected function get_null_action() { - return new ActionScheduler_NullAction(); - } - - protected function make_action_from_post( $post ) { - $hook = $post->post_title; - - $args = json_decode( $post->post_content, true ); - $this->validate_args( $args, $post->ID ); - - $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true ); - $this->validate_schedule( $schedule, $post->ID ); - - $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') ); - $group = empty( $group ) ? '' : reset($group); - - return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group ); - } - - /** - * @param string $post_status - * - * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels() - * @return string - */ - protected function get_action_status_by_post_status( $post_status ) { - - switch ( $post_status ) { - case 'publish' : - $action_status = self::STATUS_COMPLETE; - break; - case 'trash' : - $action_status = self::STATUS_CANCELED; - break; - default : - if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) { - throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) ); - } - $action_status = $post_status; - break; - } - - return $action_status; - } - - /** - * @param string $action_status - * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels() - * @return string - */ - protected function get_post_status_by_action_status( $action_status ) { - - switch ( $action_status ) { - case self::STATUS_COMPLETE : - $post_status = 'publish'; - break; - case self::STATUS_CANCELED : - $post_status = 'trash'; - break; - default : - if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) { - throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) ); - } - $post_status = $action_status; - break; - } - - return $post_status; - } - - /** - * @param string $hook - * @param array $params - * - * @return string ID of the next action matching the criteria or NULL if not found - */ - public function find_action( $hook, $params = array() ) { - $params = wp_parse_args( $params, array( - 'args' => NULL, - 'status' => ActionScheduler_Store::STATUS_PENDING, - 'group' => '', - )); - /** @var wpdb $wpdb */ - global $wpdb; - $query = "SELECT p.ID FROM {$wpdb->posts} p"; - $args = array(); - if ( !empty($params['group']) ) { - $query .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; - $query .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; - $query .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id AND t.slug=%s"; - $args[] = $params['group']; - } - $query .= " WHERE p.post_title=%s"; - $args[] = $hook; - $query .= " AND p.post_type=%s"; - $args[] = self::POST_TYPE; - if ( !is_null($params['args']) ) { - $query .= " AND p.post_content=%s"; - $args[] = json_encode($params['args']); - } - - if ( ! empty( $params['status'] ) ) { - $query .= " AND p.post_status=%s"; - $args[] = $this->get_post_status_by_action_status( $params['status'] ); - } - - switch ( $params['status'] ) { - case self::STATUS_COMPLETE: - case self::STATUS_RUNNING: - case self::STATUS_FAILED: - $order = 'DESC'; // Find the most recent action that matches - break; - case self::STATUS_PENDING: - default: - $order = 'ASC'; // Find the next action that matches - break; - } - $query .= " ORDER BY post_date_gmt $order LIMIT 1"; - - $query = $wpdb->prepare( $query, $args ); - - $id = $wpdb->get_var($query); - return $id; - } - - /** - * Returns the SQL statement to query (or count) actions. - * - * @param array $query Filtering options - * @param string $select_or_count Whether the SQL should select and return the IDs or just the row count - * @throws InvalidArgumentException if $select_or_count not count or select - * @return string SQL statement. The returned SQL is already properly escaped. - */ - protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) { - - if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) { - throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'action-scheduler')); - } - - $query = wp_parse_args( $query, array( - 'hook' => '', - 'args' => NULL, - 'date' => NULL, - 'date_compare' => '<=', - 'modified' => NULL, - 'modified_compare' => '<=', - 'group' => '', - 'status' => '', - 'claimed' => NULL, - 'per_page' => 5, - 'offset' => 0, - 'orderby' => 'date', - 'order' => 'ASC', - 'search' => '', - ) ); - - /** @var wpdb $wpdb */ - global $wpdb; - $sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID '; - $sql .= "FROM {$wpdb->posts} p"; - $sql_params = array(); - if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) { - $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; - $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; - $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; - } elseif ( ! empty( $query['group'] ) ) { - $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; - $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; - $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; - $sql .= " AND t.slug=%s"; - $sql_params[] = $query['group']; - } - $sql .= " WHERE post_type=%s"; - $sql_params[] = self::POST_TYPE; - if ( $query['hook'] ) { - $sql .= " AND p.post_title=%s"; - $sql_params[] = $query['hook']; - } - if ( !is_null($query['args']) ) { - $sql .= " AND p.post_content=%s"; - $sql_params[] = json_encode($query['args']); - } - - if ( ! empty( $query['status'] ) ) { - $sql .= " AND p.post_status=%s"; - $sql_params[] = $this->get_post_status_by_action_status( $query['status'] ); - } - - if ( $query['date'] instanceof DateTime ) { - $date = clone $query['date']; - $date->setTimezone( new DateTimeZone('UTC') ); - $date_string = $date->format('Y-m-d H:i:s'); - $comparator = $this->validate_sql_comparator($query['date_compare']); - $sql .= " AND p.post_date_gmt $comparator %s"; - $sql_params[] = $date_string; - } - - if ( $query['modified'] instanceof DateTime ) { - $modified = clone $query['modified']; - $modified->setTimezone( new DateTimeZone('UTC') ); - $date_string = $modified->format('Y-m-d H:i:s'); - $comparator = $this->validate_sql_comparator($query['modified_compare']); - $sql .= " AND p.post_modified_gmt $comparator %s"; - $sql_params[] = $date_string; - } - - if ( $query['claimed'] === TRUE ) { - $sql .= " AND p.post_password != ''"; - } elseif ( $query['claimed'] === FALSE ) { - $sql .= " AND p.post_password = ''"; - } elseif ( !is_null($query['claimed']) ) { - $sql .= " AND p.post_password = %s"; - $sql_params[] = $query['claimed']; - } - - if ( ! empty( $query['search'] ) ) { - $sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)"; - for( $i = 0; $i < 3; $i++ ) { - $sql_params[] = sprintf( '%%%s%%', $query['search'] ); - } - } - - if ( 'select' === $select_or_count ) { - switch ( $query['orderby'] ) { - case 'hook': - $orderby = 'p.post_title'; - break; - case 'group': - $orderby = 't.name'; - break; - case 'status': - $orderby = 'p.post_status'; - break; - case 'modified': - $orderby = 'p.post_modified'; - break; - case 'claim_id': - $orderby = 'p.post_password'; - break; - case 'schedule': - case 'date': - default: - $orderby = 'p.post_date_gmt'; - break; - } - if ( 'ASC' === strtoupper( $query['order'] ) ) { - $order = 'ASC'; - } else { - $order = 'DESC'; - } - $sql .= " ORDER BY $orderby $order"; - if ( $query['per_page'] > 0 ) { - $sql .= " LIMIT %d, %d"; - $sql_params[] = $query['offset']; - $sql_params[] = $query['per_page']; - } - } - - return $wpdb->prepare( $sql, $sql_params ); - } - - /** - * @param array $query - * @param string $query_type Whether to select or count the results. Default, select. - * @return string|array The IDs of actions matching the query - */ - public function query_actions( $query = array(), $query_type = 'select' ) { - /** @var wpdb $wpdb */ - global $wpdb; - - $sql = $this->get_query_actions_sql( $query, $query_type ); - - return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); - } - - /** - * Get a count of all actions in the store, grouped by status - * - * @return array - */ - public function action_counts() { - - $action_counts_by_status = array(); - $action_stati_and_labels = $this->get_status_labels(); - $posts_count_by_status = (array) wp_count_posts( self::POST_TYPE, 'readable' ); - - foreach ( $posts_count_by_status as $post_status_name => $count ) { - - try { - $action_status_name = $this->get_action_status_by_post_status( $post_status_name ); - } catch ( Exception $e ) { - // Ignore any post statuses that aren't for actions - continue; - } - if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) { - $action_counts_by_status[ $action_status_name ] = $count; - } - } - - return $action_counts_by_status; - } - - /** - * @param string $action_id - * - * @throws InvalidArgumentException - */ - public function cancel_action( $action_id ) { - $post = get_post($action_id); - if ( empty($post) || ($post->post_type != self::POST_TYPE) ) { - throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); - } - do_action( 'action_scheduler_canceled_action', $action_id ); - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); - wp_trash_post($action_id); - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); - } - - public function delete_action( $action_id ) { - $post = get_post($action_id); - if ( empty($post) || ($post->post_type != self::POST_TYPE) ) { - throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); - } - do_action( 'action_scheduler_deleted_action', $action_id ); - - wp_delete_post( $action_id, TRUE ); - } - - /** - * @param string $action_id - * - * @throws InvalidArgumentException - * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran. - */ - public function get_date( $action_id ) { - $next = $this->get_date_gmt( $action_id ); - return ActionScheduler_TimezoneHelper::set_local_timezone( $next ); - } - - /** - * @param string $action_id - * - * @throws InvalidArgumentException - * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran. - */ - public function get_date_gmt( $action_id ) { - $post = get_post($action_id); - if ( empty($post) || ($post->post_type != self::POST_TYPE) ) { - throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); - } - if ( $post->post_status == 'publish' ) { - return as_get_datetime_object($post->post_modified_gmt); - } else { - return as_get_datetime_object($post->post_date_gmt); - } - } - - /** - * @param int $max_actions - * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now. - * @param array $hooks Claim only actions with a hook or hooks. - * @param string $group Claim only actions in the given group. - * - * @return ActionScheduler_ActionClaim - * @throws RuntimeException When there is an error staking a claim. - * @throws InvalidArgumentException When the given group is not valid. - */ - public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { - $claim_id = $this->generate_claim_id(); - $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group ); - $action_ids = $this->find_actions_by_claim_id( $claim_id ); - - return new ActionScheduler_ActionClaim( $claim_id, $action_ids ); - } - - /** - * @return int - */ - public function get_claim_count(){ - global $wpdb; - - $sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')"; - $sql = $wpdb->prepare( $sql, array( self::POST_TYPE ) ); - - return $wpdb->get_var( $sql ); - } - - protected function generate_claim_id() { - $claim_id = md5(microtime(true) . rand(0,1000)); - return substr($claim_id, 0, 20); // to fit in db field with 20 char limit - } - - /** - * @param string $claim_id - * @param int $limit - * @param DateTime $before_date Should use UTC timezone. - * @param array $hooks Claim only actions with a hook or hooks. - * @param string $group Claim only actions in the given group. - * - * @return int The number of actions that were claimed - * @throws RuntimeException When there is a database error. - * @throws InvalidArgumentException When the group is invalid. - */ - protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) { - // Set up initial variables. - $date = null === $before_date ? as_get_datetime_object() : clone $before_date; - $limit_ids = ! empty( $group ); - $ids = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array(); - - // If limiting by IDs and no posts found, then return early since we have nothing to update. - if ( $limit_ids && 0 === count( $ids ) ) { - return 0; - } - - /** @var wpdb $wpdb */ - global $wpdb; - - /* - * Build up custom query to update the affected posts. Parameters are built as a separate array - * to make it easier to identify where they are in the query. - * - * We can't use $wpdb->update() here because of the "ID IN ..." clause. - */ - $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s"; - $params = array( - $claim_id, - current_time( 'mysql', true ), - current_time( 'mysql' ), - ); - - // Build initial WHERE clause. - $where = "WHERE post_type = %s AND post_status = %s AND post_password = ''"; - $params[] = self::POST_TYPE; - $params[] = ActionScheduler_Store::STATUS_PENDING; - - if ( ! empty( $hooks ) ) { - $placeholders = array_fill( 0, count( $hooks ), '%s' ); - $where .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')'; - $params = array_merge( $params, array_values( $hooks ) ); - } - - /* - * Add the IDs to the WHERE clause. IDs not escaped because they came directly from a prior DB query. - * - * If we're not limiting by IDs, then include the post_date_gmt clause. - */ - if ( $limit_ids ) { - $where .= ' AND ID IN (' . join( ',', $ids ) . ')'; - } else { - $where .= ' AND post_date_gmt <= %s'; - $params[] = $date->format( 'Y-m-d H:i:s' ); - } - - // Add the ORDER BY clause and,ms limit. - $order = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d'; - $params[] = $limit; - - // Run the query and gather results. - $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); - if ( $rows_affected === false ) { - throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); - } - - return (int) $rows_affected; - } - - /** - * Get IDs of actions within a certain group and up to a certain date/time. - * - * @param string $group The group to use in finding actions. - * @param int $limit The number of actions to retrieve. - * @param DateTime $date DateTime object representing cutoff time for actions. Actions retrieved will be - * up to and including this DateTime. - * - * @return array IDs of actions in the appropriate group and before the appropriate time. - * @throws InvalidArgumentException When the group does not exist. - */ - protected function get_actions_by_group( $group, $limit, DateTime $date ) { - // Ensure the group exists before continuing. - if ( ! term_exists( $group, self::GROUP_TAXONOMY )) { - throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) ); - } - - // Set up a query for post IDs to use later. - $query = new WP_Query(); - $query_args = array( - 'fields' => 'ids', - 'post_type' => self::POST_TYPE, - 'post_status' => ActionScheduler_Store::STATUS_PENDING, - 'has_password' => false, - 'posts_per_page' => $limit * 3, - 'suppress_filters' => true, - 'no_found_rows' => true, - 'orderby' => array( - 'menu_order' => 'ASC', - 'date' => 'ASC', - 'ID' => 'ASC', - ), - 'date_query' => array( - 'column' => 'post_date_gmt', - 'before' => $date->format( 'Y-m-d H:i' ), - 'inclusive' => true, - ), - 'tax_query' => array( - array( - 'taxonomy' => self::GROUP_TAXONOMY, - 'field' => 'slug', - 'terms' => $group, - 'include_children' => false, - ), - ), - ); - - return $query->query( $query_args ); - } - - /** - * @param string $claim_id - * @return array - */ - public function find_actions_by_claim_id( $claim_id ) { - /** @var wpdb $wpdb */ - global $wpdb; - $sql = "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s"; - $sql = $wpdb->prepare( $sql, array( self::POST_TYPE, $claim_id ) ); - $action_ids = $wpdb->get_col( $sql ); - return $action_ids; - } - - public function release_claim( ActionScheduler_ActionClaim $claim ) { - $action_ids = $this->find_actions_by_claim_id( $claim->get_id() ); - if ( empty($action_ids) ) { - return; // nothing to do - } - $action_id_string = implode(',', array_map('intval', $action_ids)); - /** @var wpdb $wpdb */ - global $wpdb; - $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s"; - $sql = $wpdb->prepare( $sql, array( $claim->get_id() ) ); - $result = $wpdb->query($sql); - if ( $result === false ) { - /* translators: %s: claim ID */ - throw new RuntimeException( sprintf( __('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id() ) ); - } - } - - /** - * @param string $action_id - */ - public function unclaim_action( $action_id ) { - /** @var wpdb $wpdb */ - global $wpdb; - $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s"; - $sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE ); - $result = $wpdb->query($sql); - if ( $result === false ) { - /* translators: %s: action ID */ - throw new RuntimeException( sprintf( __('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id ) ); - } - } - - public function mark_failure( $action_id ) { - /** @var wpdb $wpdb */ - global $wpdb; - $sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s"; - $sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE ); - $result = $wpdb->query($sql); - if ( $result === false ) { - /* translators: %s: action ID */ - throw new RuntimeException( sprintf( __('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id ) ); - } - } - - /** - * Return an action's claim ID, as stored in the post password column - * - * @param string $action_id - * @return mixed - */ - public function get_claim_id( $action_id ) { - return $this->get_post_column( $action_id, 'post_password' ); - } - - /** - * Return an action's status, as stored in the post status column - * - * @param string $action_id - * @return mixed - */ - public function get_status( $action_id ) { - $status = $this->get_post_column( $action_id, 'post_status' ); - - if ( $status === null ) { - throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) ); - } - - return $this->get_action_status_by_post_status( $status ); - } - - private function get_post_column( $action_id, $column_name ) { - /** @var \wpdb $wpdb */ - global $wpdb; - return $wpdb->get_var( $wpdb->prepare( "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE ) ); - } - - /** - * @param string $action_id - */ - public function log_execution( $action_id ) { - /** @var wpdb $wpdb */ - global $wpdb; - - $sql = "UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s"; - $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE ); - $wpdb->query($sql); - } - - /** - * Record that an action was completed. - * - * @param int $action_id ID of the completed action. - * @throws InvalidArgumentException|RuntimeException - */ - public function mark_complete( $action_id ) { - $post = get_post($action_id); - if ( empty($post) || ($post->post_type != self::POST_TYPE) ) { - throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); - } - add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 ); - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); - $result = wp_update_post(array( - 'ID' => $action_id, - 'post_status' => 'publish', - ), TRUE); - remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); - if ( is_wp_error($result) ) { - throw new RuntimeException($result->get_error_message()); - } - } - - /** - * Mark action as migrated when there is an error deleting the action. - * - * @param int $action_id Action ID. - */ - public function mark_migrated( $action_id ) { - wp_update_post( - array( - 'ID' => $action_id, - 'post_status' => 'migrated' - ) - ); - } - - /** - * Determine whether the post store can be migrated. - * - * @return bool - */ - public function migration_dependencies_met( $setting ) { - global $wpdb; - - $dependencies_met = get_transient( self::DEPENDENCIES_MET ); - if ( empty( $dependencies_met ) ) { - $found_action = $wpdb->get_var( - $wpdb->prepare( - "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > 191 LIMIT 1", - self::POST_TYPE - ) - ); - $dependencies_met = $found_action ? 'no' : 'yes'; - set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS ); - } - - return 'yes' == $dependencies_met ? $setting : false; - } - - /** - * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4. - * - * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However, - * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn - * developers of this impending requirement. - * - * @param ActionScheduler_Action $action - */ - protected function validate_action( ActionScheduler_Action $action ) { - try { - parent::validate_action( $action ); - } catch ( Exception $e ) { - $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() ); - _doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' ); - } - } - - /** - * @codeCoverageIgnore - */ - public function init() { - add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) ); - - $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar(); - $post_type_registrar->register(); - - $post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar(); - $post_status_registrar->register(); - - $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar(); - $taxonomy_registrar->register(); - } -} diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php deleted file mode 100644 index 246bc34..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php +++ /dev/null @@ -1,58 +0,0 @@ -post_status_args(), $this->post_status_running_labels() ) ); - register_post_status( ActionScheduler_Store::STATUS_FAILED, array_merge( $this->post_status_args(), $this->post_status_failed_labels() ) ); - } - - /** - * Build the args array for the post type definition - * - * @return array - */ - protected function post_status_args() { - $args = array( - 'public' => false, - 'exclude_from_search' => false, - 'show_in_admin_all_list' => true, - 'show_in_admin_status_list' => true, - ); - - return apply_filters( 'action_scheduler_post_status_args', $args ); - } - - /** - * Build the args array for the post type definition - * - * @return array - */ - protected function post_status_failed_labels() { - $labels = array( - 'label' => _x( 'Failed', 'post', 'action-scheduler' ), - /* translators: %s: count */ - 'label_count' => _n_noop( 'Failed (%s)', 'Failed (%s)', 'action-scheduler' ), - ); - - return apply_filters( 'action_scheduler_post_status_failed_labels', $labels ); - } - - /** - * Build the args array for the post type definition - * - * @return array - */ - protected function post_status_running_labels() { - $labels = array( - 'label' => _x( 'In-Progress', 'post', 'action-scheduler' ), - /* translators: %s: count */ - 'label_count' => _n_noop( 'In-Progress (%s)', 'In-Progress (%s)', 'action-scheduler' ), - ); - - return apply_filters( 'action_scheduler_post_status_running_labels', $labels ); - } -} diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php deleted file mode 100644 index 8c63bd0..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php +++ /dev/null @@ -1,50 +0,0 @@ -post_type_args() ); - } - - /** - * Build the args array for the post type definition - * - * @return array - */ - protected function post_type_args() { - $args = array( - 'label' => __( 'Scheduled Actions', 'action-scheduler' ), - 'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ), - 'public' => false, - 'map_meta_cap' => true, - 'hierarchical' => false, - 'supports' => array('title', 'editor','comments'), - 'rewrite' => false, - 'query_var' => false, - 'can_export' => true, - 'ep_mask' => EP_NONE, - 'labels' => array( - 'name' => __( 'Scheduled Actions', 'action-scheduler' ), - 'singular_name' => __( 'Scheduled Action', 'action-scheduler' ), - 'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ), - 'add_new' => __( 'Add', 'action-scheduler' ), - 'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ), - 'edit' => __( 'Edit', 'action-scheduler' ), - 'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ), - 'new_item' => __( 'New Scheduled Action', 'action-scheduler' ), - 'view' => __( 'View Action', 'action-scheduler' ), - 'view_item' => __( 'View Action', 'action-scheduler' ), - 'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ), - 'not_found' => __( 'No actions found', 'action-scheduler' ), - 'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ), - ), - ); - - $args = apply_filters('action_scheduler_post_type_args', $args); - return $args; - } -} - \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php b/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php deleted file mode 100644 index 026d625..0000000 --- a/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php +++ /dev/null @@ -1,26 +0,0 @@ -taxonomy_args() ); - } - - protected function taxonomy_args() { - $args = array( - 'label' => __('Action Group', 'action-scheduler'), - 'public' => false, - 'hierarchical' => false, - 'show_admin_column' => true, - 'query_var' => false, - 'rewrite' => false, - ); - - $args = apply_filters('action_scheduler_taxonomy_args', $args); - return $args; - } -} - \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/migration/ActionMigrator.php b/includes/libraries/action-scheduler/classes/migration/ActionMigrator.php deleted file mode 100644 index c77d083..0000000 --- a/includes/libraries/action-scheduler/classes/migration/ActionMigrator.php +++ /dev/null @@ -1,109 +0,0 @@ -source = $source_store; - $this->destination = $destination_store; - $this->log_migrator = $log_migrator; - } - - /** - * Migrate an action. - * - * @param int $source_action_id Action ID. - * - * @return int 0|new action ID - */ - public function migrate( $source_action_id ) { - try { - $action = $this->source->fetch_action( $source_action_id ); - $status = $this->source->get_status( $source_action_id ); - } catch ( \Exception $e ) { - $action = null; - $status = ''; - } - - if ( is_null( $action ) || empty( $status ) || ! $action->get_schedule()->get_date() ) { - // null action or empty status means the fetch operation failed or the action didn't exist - // null schedule means it's missing vital data - // delete it and move on - try { - $this->source->delete_action( $source_action_id ); - } catch ( \Exception $e ) { - // nothing to do, it didn't exist in the first place - } - do_action( 'action_scheduler/no_action_to_migrate', $source_action_id, $this->source, $this->destination ); - - return 0; - } - - try { - - // Make sure the last attempt date is set correctly for completed and failed actions - $last_attempt_date = ( $status !== \ActionScheduler_Store::STATUS_PENDING ) ? $this->source->get_date( $source_action_id ) : null; - - $destination_action_id = $this->destination->save_action( $action, null, $last_attempt_date ); - } catch ( \Exception $e ) { - do_action( 'action_scheduler/migrate_action_failed', $source_action_id, $this->source, $this->destination ); - - return 0; // could not save the action in the new store - } - - try { - switch ( $status ) { - case \ActionScheduler_Store::STATUS_FAILED : - $this->destination->mark_failure( $destination_action_id ); - break; - case \ActionScheduler_Store::STATUS_CANCELED : - $this->destination->cancel_action( $destination_action_id ); - break; - } - - $this->log_migrator->migrate( $source_action_id, $destination_action_id ); - $this->source->delete_action( $source_action_id ); - - $test_action = $this->source->fetch_action( $source_action_id ); - if ( ! is_a( $test_action, 'ActionScheduler_NullAction' ) ) { - throw new \RuntimeException( sprintf( __( 'Unable to remove source migrated action %s', 'action-scheduler' ), $source_action_id ) ); - } - do_action( 'action_scheduler/migrated_action', $source_action_id, $destination_action_id, $this->source, $this->destination ); - - return $destination_action_id; - } catch ( \Exception $e ) { - // could not delete from the old store - $this->source->mark_migrated( $source_action_id ); - do_action( 'action_scheduler/migrate_action_incomplete', $source_action_id, $destination_action_id, $this->source, $this->destination ); - do_action( 'action_scheduler/migrated_action', $source_action_id, $destination_action_id, $this->source, $this->destination ); - - return $destination_action_id; - } - } -} diff --git a/includes/libraries/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php b/includes/libraries/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php deleted file mode 100644 index 41c21da..0000000 --- a/includes/libraries/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php +++ /dev/null @@ -1,47 +0,0 @@ - $this->get_scheduled_date_string( $action, $last_attempt_date ), - 'last_attempt_local' => $this->get_scheduled_date_string_local( $action, $last_attempt_date ), - ]; - - $wpdb->update( $wpdb->actionscheduler_actions, $data, array( 'action_id' => $action_id ), array( '%s', '%s' ), array( '%d' ) ); - } - - return $action_id; - } catch ( \Exception $e ) { - throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 ); - } - } -} diff --git a/includes/libraries/action-scheduler/classes/migration/BatchFetcher.php b/includes/libraries/action-scheduler/classes/migration/BatchFetcher.php deleted file mode 100644 index 4872801..0000000 --- a/includes/libraries/action-scheduler/classes/migration/BatchFetcher.php +++ /dev/null @@ -1,86 +0,0 @@ -store = $source_store; - } - - /** - * Retrieve a list of actions. - * - * @param int $count The number of actions to retrieve - * - * @return int[] A list of action IDs - */ - public function fetch( $count = 10 ) { - foreach ( $this->get_query_strategies( $count ) as $query ) { - $action_ids = $this->store->query_actions( $query ); - if ( ! empty( $action_ids ) ) { - return $action_ids; - } - } - - return []; - } - - /** - * Generate a list of prioritized of action search parameters. - * - * @param int $count Number of actions to find. - * - * @return array - */ - private function get_query_strategies( $count ) { - $now = as_get_datetime_object(); - $args = [ - 'date' => $now, - 'per_page' => $count, - 'offset' => 0, - 'orderby' => 'date', - 'order' => 'ASC', - ]; - - $priorities = [ - Store::STATUS_PENDING, - Store::STATUS_FAILED, - Store::STATUS_CANCELED, - Store::STATUS_COMPLETE, - Store::STATUS_RUNNING, - '', // any other unanticipated status - ]; - - foreach ( $priorities as $status ) { - yield wp_parse_args( [ - 'status' => $status, - 'date_compare' => '<=', - ], $args ); - yield wp_parse_args( [ - 'status' => $status, - 'date_compare' => '>=', - ], $args ); - } - } -} \ No newline at end of file diff --git a/includes/libraries/action-scheduler/classes/migration/Config.php b/includes/libraries/action-scheduler/classes/migration/Config.php deleted file mode 100644 index 50f41ff..0000000 --- a/includes/libraries/action-scheduler/classes/migration/Config.php +++ /dev/null @@ -1,168 +0,0 @@ -source_store ) ) { - throw new \RuntimeException( __( 'Source store must be configured before running a migration', 'action-scheduler' ) ); - } - - return $this->source_store; - } - - /** - * Set the configured source store. - * - * @param ActionScheduler_Store $store Source store object. - */ - public function set_source_store( Store $store ) { - $this->source_store = $store; - } - - /** - * Get the configured source loger. - * - * @return ActionScheduler_Logger - */ - public function get_source_logger() { - if ( empty( $this->source_logger ) ) { - throw new \RuntimeException( __( 'Source logger must be configured before running a migration', 'action-scheduler' ) ); - } - - return $this->source_logger; - } - - /** - * Set the configured source logger. - * - * @param ActionScheduler_Logger $logger - */ - public function set_source_logger( Logger $logger ) { - $this->source_logger = $logger; - } - - /** - * Get the configured destination store. - * - * @return ActionScheduler_Store - */ - public function get_destination_store() { - if ( empty( $this->destination_store ) ) { - throw new \RuntimeException( __( 'Destination store must be configured before running a migration', 'action-scheduler' ) ); - } - - return $this->destination_store; - } - - /** - * Set the configured destination store. - * - * @param ActionScheduler_Store $store - */ - public function set_destination_store( Store $store ) { - $this->destination_store = $store; - } - - /** - * Get the configured destination logger. - * - * @return ActionScheduler_Logger - */ - public function get_destination_logger() { - if ( empty( $this->destination_logger ) ) { - throw new \RuntimeException( __( 'Destination logger must be configured before running a migration', 'action-scheduler' ) ); - } - - return $this->destination_logger; - } - - /** - * Set the configured destination logger. - * - * @param ActionScheduler_Logger $logger - */ - public function set_destination_logger( Logger $logger ) { - $this->destination_logger = $logger; - } - - /** - * Get flag indicating whether it's a dry run. - * - * @return bool - */ - public function get_dry_run() { - return $this->dry_run; - } - - /** - * Set flag indicating whether it's a dry run. - * - * @param bool $dry_run - */ - public function set_dry_run( $dry_run ) { - $this->dry_run = (bool) $dry_run; - } - - /** - * Get progress bar object. - * - * @return ActionScheduler\WPCLI\ProgressBar - */ - public function get_progress_bar() { - return $this->progress_bar; - } - - /** - * Set progress bar object. - * - * @param ActionScheduler\WPCLI\ProgressBar $progress_bar - */ - public function set_progress_bar( ProgressBar $progress_bar ) { - $this->progress_bar = $progress_bar; - } -} diff --git a/includes/libraries/action-scheduler/classes/migration/Controller.php b/includes/libraries/action-scheduler/classes/migration/Controller.php deleted file mode 100644 index 39b5a4a..0000000 --- a/includes/libraries/action-scheduler/classes/migration/Controller.php +++ /dev/null @@ -1,206 +0,0 @@ -migration_scheduler = $migration_scheduler; - $this->store_classname = ''; - } - - /** - * Set the action store class name. - * - * @param string $class Classname of the store class. - * - * @return string - */ - public function get_store_class( $class ) { - if ( \ActionScheduler_DataController::is_migration_complete() ) { - return \ActionScheduler_DataController::DATASTORE_CLASS; - } elseif ( \ActionScheduler_Store::DEFAULT_CLASS !== $class ) { - $this->store_classname = $class; - return $class; - } else { - return 'ActionScheduler_HybridStore'; - } - } - - /** - * Set the action logger class name. - * - * @param string $class Classname of the logger class. - * - * @return string - */ - public function get_logger_class( $class ) { - \ActionScheduler_Store::instance(); - - if ( $this->has_custom_datastore() ) { - $this->logger_classname = $class; - return $class; - } else { - return \ActionScheduler_DataController::LOGGER_CLASS; - } - } - - /** - * Get flag indicating whether a custom datastore is in use. - * - * @return bool - */ - public function has_custom_datastore() { - return (bool) $this->store_classname; - } - - /** - * Set up the background migration process - * - * @return void - */ - public function schedule_migration() { - if ( \ActionScheduler_DataController::is_migration_complete() || $this->migration_scheduler->is_migration_scheduled() ) { - return; - } - - $this->migration_scheduler->schedule_migration(); - } - - /** - * Get the default migration config object - * - * @return ActionScheduler\Migration\Config - */ - public function get_migration_config_object() { - static $config = null; - - if ( ! $config ) { - $source_store = $this->store_classname ? new $this->store_classname() : new \ActionScheduler_wpPostStore(); - $source_logger = $this->logger_classname ? new $this->logger_classname() : new \ActionScheduler_wpCommentLogger(); - - $config = new Config(); - $config->set_source_store( $source_store ); - $config->set_source_logger( $source_logger ); - $config->set_destination_store( new \ActionScheduler_DBStoreMigrator() ); - $config->set_destination_logger( new \ActionScheduler_DBLogger() ); - - if ( defined( 'WP_CLI' ) && WP_CLI ) { - $config->set_progress_bar( new ProgressBar( '', 0 ) ); - } - } - - return apply_filters( 'action_scheduler/migration_config', $config ); - } - - /** - * Hook dashboard migration notice. - */ - public function hook_admin_notices() { - if ( ! $this->allow_migration() || \ActionScheduler_DataController::is_migration_complete() ) { - return; - } - add_action( 'admin_notices', array( $this, 'display_migration_notice' ), 10, 0 ); - } - - /** - * Show a dashboard notice that migration is in progress. - */ - public function display_migration_notice() { - printf( '

    %s

    ', __( 'Action Scheduler migration in progress. The list of scheduled actions may be incomplete.', 'action-scheduler' ) ); - } - - /** - * Add store classes. Hook migration. - */ - private function hook() { - add_filter( 'action_scheduler_store_class', array( $this, 'get_store_class' ), 100, 1 ); - add_filter( 'action_scheduler_logger_class', array( $this, 'get_logger_class' ), 100, 1 ); - add_action( 'init', array( $this, 'maybe_hook_migration' ) ); - add_action( 'shutdown', array( $this, 'schedule_migration' ), 0, 0 ); - - // Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen - add_action( 'load-tools_page_action-scheduler', array( $this, 'hook_admin_notices' ), 10, 0 ); - add_action( 'load-woocommerce_page_wc-status', array( $this, 'hook_admin_notices' ), 10, 0 ); - } - - /** - * Possibly hook the migration scheduler action. - * - * @author Jeremy Pry - */ - public function maybe_hook_migration() { - if ( ! $this->allow_migration() || \ActionScheduler_DataController::is_migration_complete() ) { - return; - } - - $this->migration_scheduler->hook(); - } - - /** - * Allow datastores to enable migration to AS tables. - */ - public function allow_migration() { - if ( ! \ActionScheduler_DataController::dependencies_met() ) { - return false; - } - - if ( null === $this->migrate_custom_store ) { - $this->migrate_custom_store = apply_filters( 'action_scheduler_migrate_data_store', false ); - } - - return ( ! $this->has_custom_datastore() ) || $this->migrate_custom_store; - } - - /** - * Proceed with the migration if the dependencies have been met. - */ - public static function init() { - if ( \ActionScheduler_DataController::dependencies_met() ) { - self::instance()->hook(); - } - } - - /** - * Singleton factory. - */ - public static function instance() { - if ( ! isset( self::$instance ) ) { - self::$instance = new static( new Scheduler() ); - } - - return self::$instance; - } -} diff --git a/includes/libraries/action-scheduler/classes/migration/DryRun_ActionMigrator.php b/includes/libraries/action-scheduler/classes/migration/DryRun_ActionMigrator.php deleted file mode 100644 index ffc21c2..0000000 --- a/includes/libraries/action-scheduler/classes/migration/DryRun_ActionMigrator.php +++ /dev/null @@ -1,28 +0,0 @@ -source = $source_logger; - $this->destination = $destination_Logger; - } - - /** - * Migrate an action log. - * - * @param int $source_action_id Source logger object. - * @param int $destination_action_id Destination logger object. - */ - public function migrate( $source_action_id, $destination_action_id ) { - $logs = $this->source->get_logs( $source_action_id ); - foreach ( $logs as $log ) { - if ( $log->get_action_id() == $source_action_id ) { - $this->destination->log( $destination_action_id, $log->get_message(), $log->get_date() ); - } - } - } -} diff --git a/includes/libraries/action-scheduler/classes/migration/Runner.php b/includes/libraries/action-scheduler/classes/migration/Runner.php deleted file mode 100644 index 867c5de..0000000 --- a/includes/libraries/action-scheduler/classes/migration/Runner.php +++ /dev/null @@ -1,136 +0,0 @@ -source_store = $config->get_source_store(); - $this->destination_store = $config->get_destination_store(); - $this->source_logger = $config->get_source_logger(); - $this->destination_logger = $config->get_destination_logger(); - - $this->batch_fetcher = new BatchFetcher( $this->source_store ); - if ( $config->get_dry_run() ) { - $this->log_migrator = new DryRun_LogMigrator( $this->source_logger, $this->destination_logger ); - $this->action_migrator = new DryRun_ActionMigrator( $this->source_store, $this->destination_store, $this->log_migrator ); - } else { - $this->log_migrator = new LogMigrator( $this->source_logger, $this->destination_logger ); - $this->action_migrator = new ActionMigrator( $this->source_store, $this->destination_store, $this->log_migrator ); - } - - if ( defined( 'WP_CLI' ) && WP_CLI ) { - $this->progress_bar = $config->get_progress_bar(); - } - } - - /** - * Run migration batch. - * - * @param int $batch_size Optional batch size. Default 10. - * - * @return int Size of batch processed. - */ - public function run( $batch_size = 10 ) { - $batch = $this->batch_fetcher->fetch( $batch_size ); - $batch_size = count( $batch ); - - if ( ! $batch_size ) { - return 0; - } - - if ( $this->progress_bar ) { - /* translators: %d: amount of actions */ - $this->progress_bar->set_message( sprintf( _n( 'Migrating %d action', 'Migrating %d actions', $batch_size, 'action-scheduler' ), number_format_i18n( $batch_size ) ) ); - $this->progress_bar->set_count( $batch_size ); - } - - $this->migrate_actions( $batch ); - - return $batch_size; - } - - /** - * Migration a batch of actions. - * - * @param array $action_ids List of action IDs to migrate. - */ - public function migrate_actions( array $action_ids ) { - do_action( 'action_scheduler/migration_batch_starting', $action_ids ); - - \ActionScheduler::logger()->unhook_stored_action(); - $this->destination_logger->unhook_stored_action(); - - foreach ( $action_ids as $source_action_id ) { - $destination_action_id = $this->action_migrator->migrate( $source_action_id ); - if ( $destination_action_id ) { - $this->destination_logger->log( $destination_action_id, sprintf( - /* translators: 1: source action ID 2: source store class 3: destination action ID 4: destination store class */ - __( 'Migrated action with ID %1$d in %2$s to ID %3$d in %4$s', 'action-scheduler' ), - $source_action_id, - get_class( $this->source_store ), - $destination_action_id, - get_class( $this->destination_store ) - ) ); - } - - if ( $this->progress_bar ) { - $this->progress_bar->tick(); - } - } - - if ( $this->progress_bar ) { - $this->progress_bar->finish(); - } - - \ActionScheduler::logger()->hook_stored_action(); - - do_action( 'action_scheduler/migration_batch_complete', $action_ids ); - } - - /** - * Initialize destination store and logger. - */ - public function init_destination() { - $this->destination_store->init(); - $this->destination_logger->init(); - } -} diff --git a/includes/libraries/action-scheduler/classes/migration/Scheduler.php b/includes/libraries/action-scheduler/classes/migration/Scheduler.php deleted file mode 100644 index da3e5b8..0000000 --- a/includes/libraries/action-scheduler/classes/migration/Scheduler.php +++ /dev/null @@ -1,128 +0,0 @@ -get_migration_runner(); - $count = $migration_runner->run( $this->get_batch_size() ); - - if ( $count === 0 ) { - $this->mark_complete(); - } else { - $this->schedule_migration( time() + $this->get_schedule_interval() ); - } - } - - /** - * Mark the migration complete. - */ - public function mark_complete() { - $this->unschedule_migration(); - - \ActionScheduler_DataController::mark_migration_complete(); - do_action( 'action_scheduler/migration_complete' ); - } - - /** - * Get a flag indicating whether the migration is scheduled. - * - * @return bool Whether there is a pending action in the store to handle the migration - */ - public function is_migration_scheduled() { - $next = as_next_scheduled_action( self::HOOK ); - - return ! empty( $next ); - } - - /** - * Schedule the migration. - * - * @param int $when Optional timestamp to run the next migration batch. Defaults to now. - * - * @return string The action ID - */ - public function schedule_migration( $when = 0 ) { - $next = as_next_scheduled_action( self::HOOK ); - - if ( ! empty( $next ) ) { - return $next; - } - - if ( empty( $when ) ) { - $when = time(); - } - - return as_schedule_single_action( $when, self::HOOK, array(), self::GROUP ); - } - - /** - * Remove the scheduled migration action. - */ - public function unschedule_migration() { - as_unschedule_action( self::HOOK, null, self::GROUP ); - } - - /** - * Get migration batch schedule interval. - * - * @return int Seconds between migration runs. Defaults to 0 seconds to allow chaining migration via Async Runners. - */ - private function get_schedule_interval() { - return (int) apply_filters( 'action_scheduler/migration_interval', 0 ); - } - - /** - * Get migration batch size. - * - * @return int Number of actions to migrate in each batch. Defaults to 250. - */ - private function get_batch_size() { - return (int) apply_filters( 'action_scheduler/migration_batch_size', 250 ); - } - - /** - * Get migration runner object. - * - * @return Runner - */ - private function get_migration_runner() { - $config = Controller::instance()->get_migration_config_object(); - - return new Runner( $config ); - } - -} diff --git a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php b/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php deleted file mode 100644 index 840e482..0000000 --- a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php +++ /dev/null @@ -1,57 +0,0 @@ -__wakeup() for details. - **/ - private $timestamp = NULL; - - /** - * @param DateTime $after - * - * @return DateTime|null - */ - public function calculate_next( DateTime $after ) { - return null; - } - - /** - * Cancelled actions should never have a next schedule, even if get_next() - * is called with $after < $this->scheduled_date. - * - * @param DateTime $after - * @return DateTime|null - */ - public function get_next( DateTime $after ) { - return null; - } - - /** - * @return bool - */ - public function is_recurring() { - return false; - } - - /** - * Unserialize recurring schedules serialized/stored prior to AS 3.0.0 - * - * Prior to Action Scheduler 3.0.0, schedules used different property names to refer - * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp - * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 - * aligned properties and property names for better inheritance. To maintain backward - * compatibility with schedules serialized and stored prior to 3.0, we need to correctly - * map the old property names with matching visibility. - */ - public function __wakeup() { - if ( ! is_null( $this->timestamp ) ) { - $this->scheduled_timestamp = $this->timestamp; - unset( $this->timestamp ); - } - parent::__wakeup(); - } -} diff --git a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php b/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php deleted file mode 100644 index 7859307..0000000 --- a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php +++ /dev/null @@ -1,102 +0,0 @@ -__wakeup() for details. - **/ - private $start_timestamp = NULL; - - /** - * Deprecated property @see $this->__wakeup() for details. - **/ - private $cron = NULL; - - /** - * Wrapper for parent constructor to accept a cron expression string and map it to a CronExpression for this - * objects $recurrence property. - * - * @param DateTime $start The date & time to run the action at or after. If $start aligns with the CronSchedule passed via $recurrence, it will be used. If it does not align, the first matching date after it will be used. - * @param CronExpression|string $recurrence The CronExpression used to calculate the schedule's next instance. - * @param DateTime|null $first (Optional) The date & time the first instance of this interval schedule ran. Default null, meaning this is the first instance. - */ - public function __construct( DateTime $start, $recurrence, DateTime $first = null ) { - if ( ! is_a( $recurrence, 'CronExpression' ) ) { - $recurrence = CronExpression::factory( $recurrence ); - } - - // For backward compatibility, we need to make sure the date is set to the first matching cron date, not whatever date is passed in. Importantly, by passing true as the 3rd param, if $start matches the cron expression, then it will be used. This was previously handled in the now deprecated next() method. - $date = $recurrence->getNextRunDate( $start, 0, true ); - - // parent::__construct() will set this to $date by default, but that may be different to $start now. - $first = empty( $first ) ? $start : $first; - - parent::__construct( $date, $recurrence, $first ); - } - - /** - * Calculate when an instance of this schedule would start based on a given - * date & time using its the CronExpression. - * - * @param DateTime $after - * @return DateTime - */ - protected function calculate_next( DateTime $after ) { - return $this->recurrence->getNextRunDate( $after, 0, false ); - } - - /** - * @return string - */ - public function get_recurrence() { - return strval( $this->recurrence ); - } - - /** - * Serialize cron schedules with data required prior to AS 3.0.0 - * - * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to - * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp - * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 - * aligned properties and property names for better inheritance. To guard against the - * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to - * also store the data with the old property names so if it's unserialized in AS < 3.0, - * the schedule doesn't end up with a null recurrence. - * - * @return array - */ - public function __sleep() { - - $sleep_params = parent::__sleep(); - - $this->start_timestamp = $this->scheduled_timestamp; - $this->cron = $this->recurrence; - - return array_merge( $sleep_params, array( - 'start_timestamp', - 'cron' - ) ); - } - - /** - * Unserialize cron schedules serialized/stored prior to AS 3.0.0 - * - * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup(). - */ - public function __wakeup() { - if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) { - $this->scheduled_timestamp = $this->start_timestamp; - unset( $this->start_timestamp ); - } - - if ( is_null( $this->recurrence ) && ! is_null( $this->cron ) ) { - $this->recurrence = $this->cron; - unset( $this->cron ); - } - parent::__wakeup(); - } -} - diff --git a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php b/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php deleted file mode 100644 index 11a591e..0000000 --- a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php +++ /dev/null @@ -1,81 +0,0 @@ -__wakeup() for details. - **/ - private $start_timestamp = NULL; - - /** - * Deprecated property @see $this->__wakeup() for details. - **/ - private $interval_in_seconds = NULL; - - /** - * Calculate when this schedule should start after a given date & time using - * the number of seconds between recurrences. - * - * @param DateTime $after - * @return DateTime - */ - protected function calculate_next( DateTime $after ) { - $after->modify( '+' . (int) $this->get_recurrence() . ' seconds' ); - return $after; - } - - /** - * @return int - */ - public function interval_in_seconds() { - _deprecated_function( __METHOD__, '3.0.0', '(int)ActionScheduler_Abstract_RecurringSchedule::get_recurrence()' ); - return (int) $this->get_recurrence(); - } - - /** - * Serialize interval schedules with data required prior to AS 3.0.0 - * - * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to - * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp - * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 - * aligned properties and property names for better inheritance. To guard against the - * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to - * also store the data with the old property names so if it's unserialized in AS < 3.0, - * the schedule doesn't end up with a null/false/0 recurrence. - * - * @return array - */ - public function __sleep() { - - $sleep_params = parent::__sleep(); - - $this->start_timestamp = $this->scheduled_timestamp; - $this->interval_in_seconds = $this->recurrence; - - return array_merge( $sleep_params, array( - 'start_timestamp', - 'interval_in_seconds' - ) ); - } - - /** - * Unserialize interval schedules serialized/stored prior to AS 3.0.0 - * - * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup(). - */ - public function __wakeup() { - if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) { - $this->scheduled_timestamp = $this->start_timestamp; - unset( $this->start_timestamp ); - } - - if ( is_null( $this->recurrence ) && ! is_null( $this->interval_in_seconds ) ) { - $this->recurrence = $this->interval_in_seconds; - unset( $this->interval_in_seconds ); - } - parent::__wakeup(); - } -} diff --git a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php b/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php deleted file mode 100644 index 0ca9f7c..0000000 --- a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php +++ /dev/null @@ -1,28 +0,0 @@ -scheduled_date = null; - } - - /** - * This schedule has no scheduled DateTime, so we need to override the parent __sleep() - * @return array - */ - public function __sleep() { - return array(); - } - - public function __wakeup() { - $this->scheduled_date = null; - } -} diff --git a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_Schedule.php b/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_Schedule.php deleted file mode 100644 index d61a9f7..0000000 --- a/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_Schedule.php +++ /dev/null @@ -1,18 +0,0 @@ -__wakeup() for details. - **/ - private $timestamp = NULL; - - /** - * @param DateTime $after - * - * @return DateTime|null - */ - public function calculate_next( DateTime $after ) { - return null; - } - - /** - * @return bool - */ - public function is_recurring() { - return false; - } - - /** - * Serialize schedule with data required prior to AS 3.0.0 - * - * Prior to Action Scheduler 3.0.0, schedules used different property names to refer - * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp - * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 - * aligned properties and property names for better inheritance. To guard against the - * scheduled date for single actions always being seen as "now" if downgrading to - * Action Scheduler < 3.0.0, we need to also store the data with the old property names - * so if it's unserialized in AS < 3.0, the schedule doesn't end up with a null recurrence. - * - * @return array - */ - public function __sleep() { - - $sleep_params = parent::__sleep(); - - $this->timestamp = $this->scheduled_timestamp; - - return array_merge( $sleep_params, array( - 'timestamp', - ) ); - } - - /** - * Unserialize recurring schedules serialized/stored prior to AS 3.0.0 - * - * Prior to Action Scheduler 3.0.0, schedules used different property names to refer - * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp - * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 - * aligned properties and property names for better inheritance. To maintain backward - * compatibility with schedules serialized and stored prior to 3.0, we need to correctly - * map the old property names with matching visibility. - */ - public function __wakeup() { - - if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->timestamp ) ) { - $this->scheduled_timestamp = $this->timestamp; - unset( $this->timestamp ); - } - parent::__wakeup(); - } -} diff --git a/includes/libraries/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php b/includes/libraries/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php deleted file mode 100644 index d19ae3f..0000000 --- a/includes/libraries/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php +++ /dev/null @@ -1,48 +0,0 @@ -tables = [ - self::LOG_TABLE, - ]; - } - - protected function get_table_definition( $table ) { - global $wpdb; - $table_name = $wpdb->$table; - $charset_collate = $wpdb->get_charset_collate(); - $max_index_length = 191; // @see wp_get_db_schema() - switch ( $table ) { - - case self::LOG_TABLE: - - return "CREATE TABLE {$table_name} ( - log_id bigint(20) unsigned NOT NULL auto_increment, - action_id bigint(20) unsigned NOT NULL, - message text NOT NULL, - log_date_gmt datetime NOT NULL default '0000-00-00 00:00:00', - log_date_local datetime NOT NULL default '0000-00-00 00:00:00', - PRIMARY KEY (log_id), - KEY action_id (action_id), - KEY log_date_gmt (log_date_gmt) - ) $charset_collate"; - - default: - return ''; - } - } -} diff --git a/includes/libraries/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php b/includes/libraries/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php deleted file mode 100644 index b4a47f7..0000000 --- a/includes/libraries/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php +++ /dev/null @@ -1,82 +0,0 @@ -tables = [ - self::ACTIONS_TABLE, - self::CLAIMS_TABLE, - self::GROUPS_TABLE, - ]; - } - - protected function get_table_definition( $table ) { - global $wpdb; - $table_name = $wpdb->$table; - $charset_collate = $wpdb->get_charset_collate(); - $max_index_length = 191; // @see wp_get_db_schema() - switch ( $table ) { - - case self::ACTIONS_TABLE: - - return "CREATE TABLE {$table_name} ( - action_id bigint(20) unsigned NOT NULL auto_increment, - hook varchar(191) NOT NULL, - status varchar(20) NOT NULL, - scheduled_date_gmt datetime NOT NULL default '0000-00-00 00:00:00', - scheduled_date_local datetime NOT NULL default '0000-00-00 00:00:00', - args varchar($max_index_length), - schedule longtext, - group_id bigint(20) unsigned NOT NULL default '0', - attempts int(11) NOT NULL default '0', - last_attempt_gmt datetime NOT NULL default '0000-00-00 00:00:00', - last_attempt_local datetime NOT NULL default '0000-00-00 00:00:00', - claim_id bigint(20) unsigned NOT NULL default '0', - PRIMARY KEY (action_id), - KEY hook (hook($max_index_length)), - KEY status (status), - KEY scheduled_date_gmt (scheduled_date_gmt), - KEY args (args($max_index_length)), - KEY group_id (group_id), - KEY last_attempt_gmt (last_attempt_gmt), - KEY claim_id (claim_id) - ) $charset_collate"; - - case self::CLAIMS_TABLE: - - return "CREATE TABLE {$table_name} ( - claim_id bigint(20) unsigned NOT NULL auto_increment, - date_created_gmt datetime NOT NULL default '0000-00-00 00:00:00', - PRIMARY KEY (claim_id), - KEY date_created_gmt (date_created_gmt) - ) $charset_collate"; - - case self::GROUPS_TABLE: - - return "CREATE TABLE {$table_name} ( - group_id bigint(20) unsigned NOT NULL auto_increment, - slug varchar(255) NOT NULL, - PRIMARY KEY (group_id), - KEY slug (slug($max_index_length)) - ) $charset_collate"; - - default: - return ''; - } - } -} diff --git a/includes/libraries/action-scheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php b/includes/libraries/action-scheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php deleted file mode 100644 index dac17aa..0000000 --- a/includes/libraries/action-scheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php +++ /dev/null @@ -1,27 +0,0 @@ -get_date(); - $replacement_method = 'get_date()'; - } else { - $return_value = $this->get_next( $after ); - $replacement_method = 'get_next( $after )'; - } - - _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method ); - - return $return_value; - } -} diff --git a/includes/libraries/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php b/includes/libraries/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php deleted file mode 100644 index 002dc75..0000000 --- a/includes/libraries/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php +++ /dev/null @@ -1,49 +0,0 @@ -mark_failure( $action_id ); - } - - /** - * Add base hooks - * - * @since 2.2.6 - */ - protected static function hook() { - _deprecated_function( __METHOD__, '3.0.0' ); - } - - /** - * Remove base hooks - * - * @since 2.2.6 - */ - protected static function unhook() { - _deprecated_function( __METHOD__, '3.0.0' ); - } - - /** - * Get the site's local time. - * - * @deprecated 2.1.0 - * @return DateTimeZone - */ - protected function get_local_timezone() { - _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' ); - return ActionScheduler_TimezoneHelper::get_local_timezone(); - } -} diff --git a/includes/libraries/action-scheduler/deprecated/functions.php b/includes/libraries/action-scheduler/deprecated/functions.php deleted file mode 100644 index f782c4b..0000000 --- a/includes/libraries/action-scheduler/deprecated/functions.php +++ /dev/null @@ -1,126 +0,0 @@ - '' - the name of the action that will be triggered - * 'args' => NULL - the args array that will be passed with the action - * 'date' => NULL - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. - * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '=' - * 'modified' => NULL - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. - * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '=' - * 'group' => '' - the group the action belongs to - * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING - * 'claimed' => NULL - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID - * 'per_page' => 5 - Number of results to return - * 'offset' => 0 - * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date' - * 'order' => 'ASC' - * @param string $return_format OBJECT, ARRAY_A, or ids - * - * @deprecated 2.1.0 - * - * @return array - */ -function wc_get_scheduled_actions( $args = array(), $return_format = OBJECT ) { - _deprecated_function( __FUNCTION__, '2.1.0', 'as_get_scheduled_actions()' ); - return as_get_scheduled_actions( $args, $return_format ); -} diff --git a/includes/libraries/action-scheduler/functions.php b/includes/libraries/action-scheduler/functions.php deleted file mode 100644 index 19bfdb9..0000000 --- a/includes/libraries/action-scheduler/functions.php +++ /dev/null @@ -1,251 +0,0 @@ -async( $hook, $args, $group ); -} - -/** - * Schedule an action to run one time - * - * @param int $timestamp When the job will run - * @param string $hook The hook to trigger - * @param array $args Arguments to pass when the hook triggers - * @param string $group The group to assign this job to - * - * @return string The job ID - */ -function as_schedule_single_action( $timestamp, $hook, $args = array(), $group = '' ) { - return ActionScheduler::factory()->single( $hook, $args, $timestamp, $group ); -} - -/** - * Schedule a recurring action - * - * @param int $timestamp When the first instance of the job will run - * @param int $interval_in_seconds How long to wait between runs - * @param string $hook The hook to trigger - * @param array $args Arguments to pass when the hook triggers - * @param string $group The group to assign this job to - * - * @return string The job ID - */ -function as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook, $args = array(), $group = '' ) { - return ActionScheduler::factory()->recurring( $hook, $args, $timestamp, $interval_in_seconds, $group ); -} - -/** - * Schedule an action that recurs on a cron-like schedule. - * - * @param int $base_timestamp The first instance of the action will be scheduled - * to run at a time calculated after this timestamp matching the cron - * expression. This can be used to delay the first instance of the action. - * @param string $schedule A cron-link schedule string - * @see http://en.wikipedia.org/wiki/Cron - * * * * * * * - * ┬ ┬ ┬ ┬ ┬ ┬ - * | | | | | | - * | | | | | + year [optional] - * | | | | +----- day of week (0 - 7) (Sunday=0 or 7) - * | | | +---------- month (1 - 12) - * | | +--------------- day of month (1 - 31) - * | +-------------------- hour (0 - 23) - * +------------------------- min (0 - 59) - * @param string $hook The hook to trigger - * @param array $args Arguments to pass when the hook triggers - * @param string $group The group to assign this job to - * - * @return string The job ID - */ -function as_schedule_cron_action( $timestamp, $schedule, $hook, $args = array(), $group = '' ) { - return ActionScheduler::factory()->cron( $hook, $args, $timestamp, $schedule, $group ); -} - -/** - * Cancel the next occurrence of a scheduled action. - * - * While only the next instance of a recurring or cron action is unscheduled by this method, that will also prevent - * all future instances of that recurring or cron action from being run. Recurring and cron actions are scheduled in - * a sequence instead of all being scheduled at once. Each successive occurrence of a recurring action is scheduled - * only after the former action is run. If the next instance is never run, because it's unscheduled by this function, - * then the following instance will never be scheduled (or exist), which is effectively the same as being unscheduled - * by this method also. - * - * @param string $hook The hook that the job will trigger - * @param array $args Args that would have been passed to the job - * @param string $group - * - * @return string The scheduled action ID if a scheduled action was found, or empty string if no matching action found. - */ -function as_unschedule_action( $hook, $args = array(), $group = '' ) { - $params = array(); - if ( is_array($args) ) { - $params['args'] = $args; - } - if ( !empty($group) ) { - $params['group'] = $group; - } - $job_id = ActionScheduler::store()->find_action( $hook, $params ); - - if ( ! empty( $job_id ) ) { - ActionScheduler::store()->cancel_action( $job_id ); - } - - return $job_id; -} - -/** - * Cancel all occurrences of a scheduled action. - * - * @param string $hook The hook that the job will trigger - * @param array $args Args that would have been passed to the job - * @param string $group - */ -function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) { - if ( empty( $args ) ) { - if ( ! empty( $hook ) && empty( $group ) ) { - ActionScheduler_Store::instance()->cancel_actions_by_hook( $hook ); - return; - } - if ( ! empty( $group ) && empty( $hook ) ) { - ActionScheduler_Store::instance()->cancel_actions_by_group( $group ); - return; - } - } - do { - $unscheduled_action = as_unschedule_action( $hook, $args, $group ); - } while ( ! empty( $unscheduled_action ) ); -} - -/** - * Check if there is an existing action in the queue with a given hook, args and group combination. - * - * An action in the queue could be pending, in-progress or aysnc. If the is pending for a time in - * future, its scheduled date will be returned as a timestamp. If it is currently being run, or an - * async action sitting in the queue waiting to be processed, in which case boolean true will be - * returned. Or there may be no async, in-progress or pending action for this hook, in which case, - * boolean false will be the return value. - * - * @param string $hook - * @param array $args - * @param string $group - * - * @return int|bool The timestamp for the next occurrence of a pending scheduled action, true for an async or in-progress action or false if there is no matching action. - */ -function as_next_scheduled_action( $hook, $args = NULL, $group = '' ) { - $params = array(); - if ( is_array($args) ) { - $params['args'] = $args; - } - if ( !empty($group) ) { - $params['group'] = $group; - } - - $params['status'] = ActionScheduler_Store::STATUS_RUNNING; - $job_id = ActionScheduler::store()->find_action( $hook, $params ); - if ( ! empty( $job_id ) ) { - return true; - } - - $params['status'] = ActionScheduler_Store::STATUS_PENDING; - $job_id = ActionScheduler::store()->find_action( $hook, $params ); - if ( empty($job_id) ) { - return false; - } - $job = ActionScheduler::store()->fetch_action( $job_id ); - $scheduled_date = $job->get_schedule()->get_date(); - if ( $scheduled_date ) { - return (int) $scheduled_date->format( 'U' ); - } elseif ( NULL === $scheduled_date ) { // pending async action with NullSchedule - return true; - } - return false; -} - -/** - * Find scheduled actions - * - * @param array $args Possible arguments, with their default values: - * 'hook' => '' - the name of the action that will be triggered - * 'args' => NULL - the args array that will be passed with the action - * 'date' => NULL - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. - * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '=' - * 'modified' => NULL - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. - * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '=' - * 'group' => '' - the group the action belongs to - * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING - * 'claimed' => NULL - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID - * 'per_page' => 5 - Number of results to return - * 'offset' => 0 - * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date' - * 'order' => 'ASC' - * - * @param string $return_format OBJECT, ARRAY_A, or ids - * - * @return array - */ -function as_get_scheduled_actions( $args = array(), $return_format = OBJECT ) { - $store = ActionScheduler::store(); - foreach ( array('date', 'modified') as $key ) { - if ( isset($args[$key]) ) { - $args[$key] = as_get_datetime_object($args[$key]); - } - } - $ids = $store->query_actions( $args ); - - if ( $return_format == 'ids' || $return_format == 'int' ) { - return $ids; - } - - $actions = array(); - foreach ( $ids as $action_id ) { - $actions[$action_id] = $store->fetch_action( $action_id ); - } - - if ( $return_format == ARRAY_A ) { - foreach ( $actions as $action_id => $action_object ) { - $actions[$action_id] = get_object_vars($action_object); - } - } - - return $actions; -} - -/** - * Helper function to create an instance of DateTime based on a given - * string and timezone. By default, will return the current date/time - * in the UTC timezone. - * - * Needed because new DateTime() called without an explicit timezone - * will create a date/time in PHP's timezone, but we need to have - * assurance that a date/time uses the right timezone (which we almost - * always want to be UTC), which means we need to always include the - * timezone when instantiating datetimes rather than leaving it up to - * the PHP default. - * - * @param mixed $date_string A date/time string. Valid formats are explained in http://php.net/manual/en/datetime.formats.php - * @param string $timezone A timezone identifier, like UTC or Europe/Lisbon. The list of valid identifiers is available http://php.net/manual/en/timezones.php - * - * @return ActionScheduler_DateTime - */ -function as_get_datetime_object( $date_string = null, $timezone = 'UTC' ) { - if ( is_object( $date_string ) && $date_string instanceof DateTime ) { - $date = new ActionScheduler_DateTime( $date_string->format( 'Y-m-d H:i:s' ), new DateTimeZone( $timezone ) ); - } elseif ( is_numeric( $date_string ) ) { - $date = new ActionScheduler_DateTime( '@' . $date_string, new DateTimeZone( $timezone ) ); - } else { - $date = new ActionScheduler_DateTime( $date_string, new DateTimeZone( $timezone ) ); - } - return $date; -} diff --git a/includes/libraries/action-scheduler/lib/WP_Async_Request.php b/includes/libraries/action-scheduler/lib/WP_Async_Request.php deleted file mode 100644 index d7dea1c..0000000 --- a/includes/libraries/action-scheduler/lib/WP_Async_Request.php +++ /dev/null @@ -1,170 +0,0 @@ -identifier = $this->prefix . '_' . $this->action; - - add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) ); - add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) ); - } - - /** - * Set data used during the request - * - * @param array $data Data. - * - * @return $this - */ - public function data( $data ) { - $this->data = $data; - - return $this; - } - - /** - * Dispatch the async request - * - * @return array|WP_Error - */ - public function dispatch() { - $url = add_query_arg( $this->get_query_args(), $this->get_query_url() ); - $args = $this->get_post_args(); - - return wp_remote_post( esc_url_raw( $url ), $args ); - } - - /** - * Get query args - * - * @return array - */ - protected function get_query_args() { - if ( property_exists( $this, 'query_args' ) ) { - return $this->query_args; - } - - return array( - 'action' => $this->identifier, - 'nonce' => wp_create_nonce( $this->identifier ), - ); - } - - /** - * Get query URL - * - * @return string - */ - protected function get_query_url() { - if ( property_exists( $this, 'query_url' ) ) { - return $this->query_url; - } - - return admin_url( 'admin-ajax.php' ); - } - - /** - * Get post args - * - * @return array - */ - protected function get_post_args() { - if ( property_exists( $this, 'post_args' ) ) { - return $this->post_args; - } - - return array( - 'timeout' => 0.01, - 'blocking' => false, - 'body' => $this->data, - 'cookies' => $_COOKIE, - 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), - ); - } - - /** - * Maybe handle - * - * Check for correct nonce and pass to handler. - */ - public function maybe_handle() { - // Don't lock up other requests while processing - session_write_close(); - - check_ajax_referer( $this->identifier, 'nonce' ); - - $this->handle(); - - wp_die(); - } - - /** - * Handle - * - * Override this method to perform any actions required - * during the async request. - */ - abstract protected function handle(); - - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression.php deleted file mode 100755 index 7f33c37..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression.php +++ /dev/null @@ -1,318 +0,0 @@ - - * @link http://en.wikipedia.org/wiki/Cron - */ -class CronExpression -{ - const MINUTE = 0; - const HOUR = 1; - const DAY = 2; - const MONTH = 3; - const WEEKDAY = 4; - const YEAR = 5; - - /** - * @var array CRON expression parts - */ - private $cronParts; - - /** - * @var CronExpression_FieldFactory CRON field factory - */ - private $fieldFactory; - - /** - * @var array Order in which to test of cron parts - */ - private static $order = array(self::YEAR, self::MONTH, self::DAY, self::WEEKDAY, self::HOUR, self::MINUTE); - - /** - * Factory method to create a new CronExpression. - * - * @param string $expression The CRON expression to create. There are - * several special predefined values which can be used to substitute the - * CRON expression: - * - * @yearly, @annually) - Run once a year, midnight, Jan. 1 - 0 0 1 1 * - * @monthly - Run once a month, midnight, first of month - 0 0 1 * * - * @weekly - Run once a week, midnight on Sun - 0 0 * * 0 - * @daily - Run once a day, midnight - 0 0 * * * - * @hourly - Run once an hour, first minute - 0 * * * * - * -*@param CronExpression_FieldFactory $fieldFactory (optional) Field factory to use - * - * @return CronExpression - */ - public static function factory($expression, CronExpression_FieldFactory $fieldFactory = null) - { - $mappings = array( - '@yearly' => '0 0 1 1 *', - '@annually' => '0 0 1 1 *', - '@monthly' => '0 0 1 * *', - '@weekly' => '0 0 * * 0', - '@daily' => '0 0 * * *', - '@hourly' => '0 * * * *' - ); - - if (isset($mappings[$expression])) { - $expression = $mappings[$expression]; - } - - return new self($expression, $fieldFactory ? $fieldFactory : new CronExpression_FieldFactory()); - } - - /** - * Parse a CRON expression - * - * @param string $expression CRON expression (e.g. '8 * * * *') - * @param CronExpression_FieldFactory $fieldFactory Factory to create cron fields - */ - public function __construct($expression, CronExpression_FieldFactory $fieldFactory) - { - $this->fieldFactory = $fieldFactory; - $this->setExpression($expression); - } - - /** - * Set or change the CRON expression - * - * @param string $value CRON expression (e.g. 8 * * * *) - * - * @return CronExpression - * @throws InvalidArgumentException if not a valid CRON expression - */ - public function setExpression($value) - { - $this->cronParts = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY); - if (count($this->cronParts) < 5) { - throw new InvalidArgumentException( - $value . ' is not a valid CRON expression' - ); - } - - foreach ($this->cronParts as $position => $part) { - $this->setPart($position, $part); - } - - return $this; - } - - /** - * Set part of the CRON expression - * - * @param int $position The position of the CRON expression to set - * @param string $value The value to set - * - * @return CronExpression - * @throws InvalidArgumentException if the value is not valid for the part - */ - public function setPart($position, $value) - { - if (!$this->fieldFactory->getField($position)->validate($value)) { - throw new InvalidArgumentException( - 'Invalid CRON field value ' . $value . ' as position ' . $position - ); - } - - $this->cronParts[$position] = $value; - - return $this; - } - - /** - * Get a next run date relative to the current date or a specific date - * - * @param string|DateTime $currentTime (optional) Relative calculation date - * @param int $nth (optional) Number of matches to skip before returning a - * matching next run date. 0, the default, will return the current - * date and time if the next run date falls on the current date and - * time. Setting this value to 1 will skip the first match and go to - * the second match. Setting this value to 2 will skip the first 2 - * matches and so on. - * @param bool $allowCurrentDate (optional) Set to TRUE to return the - * current date if it matches the cron expression - * - * @return DateTime - * @throws RuntimeException on too many iterations - */ - public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) - { - return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate); - } - - /** - * Get a previous run date relative to the current date or a specific date - * - * @param string|DateTime $currentTime (optional) Relative calculation date - * @param int $nth (optional) Number of matches to skip before returning - * @param bool $allowCurrentDate (optional) Set to TRUE to return the - * current date if it matches the cron expression - * - * @return DateTime - * @throws RuntimeException on too many iterations - * @see CronExpression::getNextRunDate - */ - public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) - { - return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate); - } - - /** - * Get multiple run dates starting at the current date or a specific date - * - * @param int $total Set the total number of dates to calculate - * @param string|DateTime $currentTime (optional) Relative calculation date - * @param bool $invert (optional) Set to TRUE to retrieve previous dates - * @param bool $allowCurrentDate (optional) Set to TRUE to return the - * current date if it matches the cron expression - * - * @return array Returns an array of run dates - */ - public function getMultipleRunDates($total, $currentTime = 'now', $invert = false, $allowCurrentDate = false) - { - $matches = array(); - for ($i = 0; $i < max(0, $total); $i++) { - $matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate); - } - - return $matches; - } - - /** - * Get all or part of the CRON expression - * - * @param string $part (optional) Specify the part to retrieve or NULL to - * get the full cron schedule string. - * - * @return string|null Returns the CRON expression, a part of the - * CRON expression, or NULL if the part was specified but not found - */ - public function getExpression($part = null) - { - if (null === $part) { - return implode(' ', $this->cronParts); - } elseif (array_key_exists($part, $this->cronParts)) { - return $this->cronParts[$part]; - } - - return null; - } - - /** - * Helper method to output the full expression. - * - * @return string Full CRON expression - */ - public function __toString() - { - return $this->getExpression(); - } - - /** - * Determine if the cron is due to run based on the current date or a - * specific date. This method assumes that the current number of - * seconds are irrelevant, and should be called once per minute. - * - * @param string|DateTime $currentTime (optional) Relative calculation date - * - * @return bool Returns TRUE if the cron is due to run or FALSE if not - */ - public function isDue($currentTime = 'now') - { - if ('now' === $currentTime) { - $currentDate = date('Y-m-d H:i'); - $currentTime = strtotime($currentDate); - } elseif ($currentTime instanceof DateTime) { - $currentDate = $currentTime->format('Y-m-d H:i'); - $currentTime = strtotime($currentDate); - } else { - $currentTime = new DateTime($currentTime); - $currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0); - $currentDate = $currentTime->format('Y-m-d H:i'); - $currentTime = (int)($currentTime->getTimestamp()); - } - - return $this->getNextRunDate($currentDate, 0, true)->getTimestamp() == $currentTime; - } - - /** - * Get the next or previous run date of the expression relative to a date - * - * @param string|DateTime $currentTime (optional) Relative calculation date - * @param int $nth (optional) Number of matches to skip before returning - * @param bool $invert (optional) Set to TRUE to go backwards in time - * @param bool $allowCurrentDate (optional) Set to TRUE to return the - * current date if it matches the cron expression - * - * @return DateTime - * @throws RuntimeException on too many iterations - */ - protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false) - { - if ($currentTime instanceof DateTime) { - $currentDate = $currentTime; - } else { - $currentDate = new DateTime($currentTime ? $currentTime : 'now'); - $currentDate->setTimezone(new DateTimeZone(date_default_timezone_get())); - } - - $currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0); - $nextRun = clone $currentDate; - $nth = (int) $nth; - - // Set a hard limit to bail on an impossible date - for ($i = 0; $i < 1000; $i++) { - - foreach (self::$order as $position) { - $part = $this->getExpression($position); - if (null === $part) { - continue; - } - - $satisfied = false; - // Get the field object used to validate this part - $field = $this->fieldFactory->getField($position); - // Check if this is singular or a list - if (strpos($part, ',') === false) { - $satisfied = $field->isSatisfiedBy($nextRun, $part); - } else { - foreach (array_map('trim', explode(',', $part)) as $listPart) { - if ($field->isSatisfiedBy($nextRun, $listPart)) { - $satisfied = true; - break; - } - } - } - - // If the field is not satisfied, then start over - if (!$satisfied) { - $field->increment($nextRun, $invert); - continue 2; - } - } - - // Skip this match if needed - if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) { - $this->fieldFactory->getField(0)->increment($nextRun, $invert); - continue; - } - - return $nextRun; - } - - // @codeCoverageIgnoreStart - throw new RuntimeException('Impossible CRON expression'); - // @codeCoverageIgnoreEnd - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_AbstractField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_AbstractField.php deleted file mode 100755 index f8d5c00..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_AbstractField.php +++ /dev/null @@ -1,100 +0,0 @@ - - */ -abstract class CronExpression_AbstractField implements CronExpression_FieldInterface -{ - /** - * Check to see if a field is satisfied by a value - * - * @param string $dateValue Date value to check - * @param string $value Value to test - * - * @return bool - */ - public function isSatisfied($dateValue, $value) - { - if ($this->isIncrementsOfRanges($value)) { - return $this->isInIncrementsOfRanges($dateValue, $value); - } elseif ($this->isRange($value)) { - return $this->isInRange($dateValue, $value); - } - - return $value == '*' || $dateValue == $value; - } - - /** - * Check if a value is a range - * - * @param string $value Value to test - * - * @return bool - */ - public function isRange($value) - { - return strpos($value, '-') !== false; - } - - /** - * Check if a value is an increments of ranges - * - * @param string $value Value to test - * - * @return bool - */ - public function isIncrementsOfRanges($value) - { - return strpos($value, '/') !== false; - } - - /** - * Test if a value is within a range - * - * @param string $dateValue Set date value - * @param string $value Value to test - * - * @return bool - */ - public function isInRange($dateValue, $value) - { - $parts = array_map('trim', explode('-', $value, 2)); - - return $dateValue >= $parts[0] && $dateValue <= $parts[1]; - } - - /** - * Test if a value is within an increments of ranges (offset[-to]/step size) - * - * @param string $dateValue Set date value - * @param string $value Value to test - * - * @return bool - */ - public function isInIncrementsOfRanges($dateValue, $value) - { - $parts = array_map('trim', explode('/', $value, 2)); - $stepSize = isset($parts[1]) ? $parts[1] : 0; - if ($parts[0] == '*' || $parts[0] === '0') { - return (int) $dateValue % $stepSize == 0; - } - - $range = explode('-', $parts[0], 2); - $offset = $range[0]; - $to = isset($range[1]) ? $range[1] : $dateValue; - // Ensure that the date value is within the range - if ($dateValue < $offset || $dateValue > $to) { - return false; - } - - for ($i = $offset; $i <= $to; $i+= $stepSize) { - if ($i == $dateValue) { - return true; - } - } - - return false; - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfMonthField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfMonthField.php deleted file mode 100755 index 40c1d6c..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfMonthField.php +++ /dev/null @@ -1,110 +0,0 @@ - - */ -class CronExpression_DayOfMonthField extends CronExpression_AbstractField -{ - /** - * Get the nearest day of the week for a given day in a month - * - * @param int $currentYear Current year - * @param int $currentMonth Current month - * @param int $targetDay Target day of the month - * - * @return DateTime Returns the nearest date - */ - private static function getNearestWeekday($currentYear, $currentMonth, $targetDay) - { - $tday = str_pad($targetDay, 2, '0', STR_PAD_LEFT); - $target = new DateTime("$currentYear-$currentMonth-$tday"); - $currentWeekday = (int) $target->format('N'); - - if ($currentWeekday < 6) { - return $target; - } - - $lastDayOfMonth = $target->format('t'); - - foreach (array(-1, 1, -2, 2) as $i) { - $adjusted = $targetDay + $i; - if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) { - $target->setDate($currentYear, $currentMonth, $adjusted); - if ($target->format('N') < 6 && $target->format('m') == $currentMonth) { - return $target; - } - } - } - } - - /** - * {@inheritdoc} - */ - public function isSatisfiedBy(DateTime $date, $value) - { - // ? states that the field value is to be skipped - if ($value == '?') { - return true; - } - - $fieldValue = $date->format('d'); - - // Check to see if this is the last day of the month - if ($value == 'L') { - return $fieldValue == $date->format('t'); - } - - // Check to see if this is the nearest weekday to a particular value - if (strpos($value, 'W')) { - // Parse the target day - $targetDay = substr($value, 0, strpos($value, 'W')); - // Find out if the current day is the nearest day of the week - return $date->format('j') == self::getNearestWeekday( - $date->format('Y'), - $date->format('m'), - $targetDay - )->format('j'); - } - - return $this->isSatisfied($date->format('d'), $value); - } - - /** - * {@inheritdoc} - */ - public function increment(DateTime $date, $invert = false) - { - if ($invert) { - $date->modify('previous day'); - $date->setTime(23, 59); - } else { - $date->modify('next day'); - $date->setTime(0, 0); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function validate($value) - { - return (bool) preg_match('/[\*,\/\-\?LW0-9A-Za-z]+/', $value); - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfWeekField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfWeekField.php deleted file mode 100755 index e9f68a7..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfWeekField.php +++ /dev/null @@ -1,124 +0,0 @@ - - */ -class CronExpression_DayOfWeekField extends CronExpression_AbstractField -{ - /** - * {@inheritdoc} - */ - public function isSatisfiedBy(DateTime $date, $value) - { - if ($value == '?') { - return true; - } - - // Convert text day of the week values to integers - $value = str_ireplace( - array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'), - range(0, 6), - $value - ); - - $currentYear = $date->format('Y'); - $currentMonth = $date->format('m'); - $lastDayOfMonth = $date->format('t'); - - // Find out if this is the last specific weekday of the month - if (strpos($value, 'L')) { - $weekday = str_replace('7', '0', substr($value, 0, strpos($value, 'L'))); - $tdate = clone $date; - $tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth); - while ($tdate->format('w') != $weekday) { - $tdate->setDate($currentYear, $currentMonth, --$lastDayOfMonth); - } - - return $date->format('j') == $lastDayOfMonth; - } - - // Handle # hash tokens - if (strpos($value, '#')) { - list($weekday, $nth) = explode('#', $value); - // Validate the hash fields - if ($weekday < 1 || $weekday > 5) { - throw new InvalidArgumentException("Weekday must be a value between 1 and 5. {$weekday} given"); - } - if ($nth > 5) { - throw new InvalidArgumentException('There are never more than 5 of a given weekday in a month'); - } - // The current weekday must match the targeted weekday to proceed - if ($date->format('N') != $weekday) { - return false; - } - - $tdate = clone $date; - $tdate->setDate($currentYear, $currentMonth, 1); - $dayCount = 0; - $currentDay = 1; - while ($currentDay < $lastDayOfMonth + 1) { - if ($tdate->format('N') == $weekday) { - if (++$dayCount >= $nth) { - break; - } - } - $tdate->setDate($currentYear, $currentMonth, ++$currentDay); - } - - return $date->format('j') == $currentDay; - } - - // Handle day of the week values - if (strpos($value, '-')) { - $parts = explode('-', $value); - if ($parts[0] == '7') { - $parts[0] = '0'; - } elseif ($parts[1] == '0') { - $parts[1] = '7'; - } - $value = implode('-', $parts); - } - - // Test to see which Sunday to use -- 0 == 7 == Sunday - $format = in_array(7, str_split($value)) ? 'N' : 'w'; - $fieldValue = $date->format($format); - - return $this->isSatisfied($fieldValue, $value); - } - - /** - * {@inheritdoc} - */ - public function increment(DateTime $date, $invert = false) - { - if ($invert) { - $date->modify('-1 day'); - $date->setTime(23, 59, 0); - } else { - $date->modify('+1 day'); - $date->setTime(0, 0, 0); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function validate($value) - { - return (bool) preg_match('/[\*,\/\-0-9A-Z]+/', $value); - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldFactory.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldFactory.php deleted file mode 100755 index 556ba1a..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldFactory.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @link http://en.wikipedia.org/wiki/Cron - */ -class CronExpression_FieldFactory -{ - /** - * @var array Cache of instantiated fields - */ - private $fields = array(); - - /** - * Get an instance of a field object for a cron expression position - * - * @param int $position CRON expression position value to retrieve - * - * @return CronExpression_FieldInterface - * @throws InvalidArgumentException if a position is not valid - */ - public function getField($position) - { - if (!isset($this->fields[$position])) { - switch ($position) { - case 0: - $this->fields[$position] = new CronExpression_MinutesField(); - break; - case 1: - $this->fields[$position] = new CronExpression_HoursField(); - break; - case 2: - $this->fields[$position] = new CronExpression_DayOfMonthField(); - break; - case 3: - $this->fields[$position] = new CronExpression_MonthField(); - break; - case 4: - $this->fields[$position] = new CronExpression_DayOfWeekField(); - break; - case 5: - $this->fields[$position] = new CronExpression_YearField(); - break; - default: - throw new InvalidArgumentException( - $position . ' is not a valid position' - ); - } - } - - return $this->fields[$position]; - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldInterface.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldInterface.php deleted file mode 100755 index 5d5109b..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldInterface.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -interface CronExpression_FieldInterface -{ - /** - * Check if the respective value of a DateTime field satisfies a CRON exp - * - * @param DateTime $date DateTime object to check - * @param string $value CRON expression to test against - * - * @return bool Returns TRUE if satisfied, FALSE otherwise - */ - public function isSatisfiedBy(DateTime $date, $value); - - /** - * When a CRON expression is not satisfied, this method is used to increment - * or decrement a DateTime object by the unit of the cron field - * - * @param DateTime $date DateTime object to change - * @param bool $invert (optional) Set to TRUE to decrement - * - * @return CronExpression_FieldInterface - */ - public function increment(DateTime $date, $invert = false); - - /** - * Validates a CRON expression for a given field - * - * @param string $value CRON expression value to validate - * - * @return bool Returns TRUE if valid, FALSE otherwise - */ - public function validate($value); -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_HoursField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_HoursField.php deleted file mode 100755 index 088ca73..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_HoursField.php +++ /dev/null @@ -1,47 +0,0 @@ - - */ -class CronExpression_HoursField extends CronExpression_AbstractField -{ - /** - * {@inheritdoc} - */ - public function isSatisfiedBy(DateTime $date, $value) - { - return $this->isSatisfied($date->format('H'), $value); - } - - /** - * {@inheritdoc} - */ - public function increment(DateTime $date, $invert = false) - { - // Change timezone to UTC temporarily. This will - // allow us to go back or forwards and hour even - // if DST will be changed between the hours. - $timezone = $date->getTimezone(); - $date->setTimezone(new DateTimeZone('UTC')); - if ($invert) { - $date->modify('-1 hour'); - $date->setTime($date->format('H'), 59); - } else { - $date->modify('+1 hour'); - $date->setTime($date->format('H'), 0); - } - $date->setTimezone($timezone); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function validate($value) - { - return (bool) preg_match('/[\*,\/\-0-9]+/', $value); - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MinutesField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MinutesField.php deleted file mode 100755 index 436acf2..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MinutesField.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -class CronExpression_MinutesField extends CronExpression_AbstractField -{ - /** - * {@inheritdoc} - */ - public function isSatisfiedBy(DateTime $date, $value) - { - return $this->isSatisfied($date->format('i'), $value); - } - - /** - * {@inheritdoc} - */ - public function increment(DateTime $date, $invert = false) - { - if ($invert) { - $date->modify('-1 minute'); - } else { - $date->modify('+1 minute'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function validate($value) - { - return (bool) preg_match('/[\*,\/\-0-9]+/', $value); - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MonthField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MonthField.php deleted file mode 100755 index d3deb12..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MonthField.php +++ /dev/null @@ -1,55 +0,0 @@ - - */ -class CronExpression_MonthField extends CronExpression_AbstractField -{ - /** - * {@inheritdoc} - */ - public function isSatisfiedBy(DateTime $date, $value) - { - // Convert text month values to integers - $value = str_ireplace( - array( - 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', - 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' - ), - range(1, 12), - $value - ); - - return $this->isSatisfied($date->format('m'), $value); - } - - /** - * {@inheritdoc} - */ - public function increment(DateTime $date, $invert = false) - { - if ($invert) { - // $date->modify('last day of previous month'); // remove for php 5.2 compat - $date->modify('previous month'); - $date->modify($date->format('Y-m-t')); - $date->setTime(23, 59); - } else { - //$date->modify('first day of next month'); // remove for php 5.2 compat - $date->modify('next month'); - $date->modify($date->format('Y-m-01')); - $date->setTime(0, 0); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function validate($value) - { - return (bool) preg_match('/[\*,\/\-0-9A-Z]+/', $value); - } -} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_YearField.php b/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_YearField.php deleted file mode 100755 index f11562e..0000000 --- a/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_YearField.php +++ /dev/null @@ -1,43 +0,0 @@ - - */ -class CronExpression_YearField extends CronExpression_AbstractField -{ - /** - * {@inheritdoc} - */ - public function isSatisfiedBy(DateTime $date, $value) - { - return $this->isSatisfied($date->format('Y'), $value); - } - - /** - * {@inheritdoc} - */ - public function increment(DateTime $date, $invert = false) - { - if ($invert) { - $date->modify('-1 year'); - $date->setDate($date->format('Y'), 12, 31); - $date->setTime(23, 59, 0); - } else { - $date->modify('+1 year'); - $date->setDate($date->format('Y'), 1, 1); - $date->setTime(0, 0, 0); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function validate($value) - { - return (bool) preg_match('/[\*,\/\-0-9]+/', $value); - } -} diff --git a/includes/libraries/class-wc-datetime.php b/includes/libraries/class-wc-datetime.php deleted file mode 100644 index f36c14e..0000000 --- a/includes/libraries/class-wc-datetime.php +++ /dev/null @@ -1,73 +0,0 @@ -format( DATE_ATOM ); - } - - /** - * Missing in PHP 5.2. - * - * @since 3.0.0 - * @return int - */ - public function getTimestamp() { - return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' ); - } - - /** - * Get the timestamp with the WordPress timezone offset added or subtracted. - * - * @since 3.0.0 - * @return int - */ - public function getOffsetTimestamp() { - return $this->getTimestamp() + $this->getOffset(); - } - - /** - * Format a date based on the offset timestamp. - * - * @since 3.0.0 - * @param string $format - * @return string - */ - public function date( $format ) { - return gmdate( $format, $this->getOffsetTimestamp() ); - } - - /** - * Return a localised date based on offset timestamp. Wrapper for date_i18n function. - * - * @since 3.0.0 - * @param string $format - * @return string - */ - public function date_i18n( $format = 'Y-m-d' ) { - return date_i18n( $format, $this->getOffsetTimestamp() ); - } -} diff --git a/includes/admin/meta-boxes/class-wcs-meta-box-payment-retries.php b/includes/payment-retry/admin/class-wcs-meta-box-payment-retries.php similarity index 90% rename from includes/admin/meta-boxes/class-wcs-meta-box-payment-retries.php rename to includes/payment-retry/admin/class-wcs-meta-box-payment-retries.php index 25e0ca1..f90e183 100644 --- a/includes/admin/meta-boxes/class-wcs-meta-box-payment-retries.php +++ b/includes/payment-retry/admin/class-wcs-meta-box-payment-retries.php @@ -28,7 +28,7 @@ class WCS_Meta_Box_Payment_Retries { $retries = WCS_Retry_Manager::store()->get_retries_for_order( $post->ID ); - include_once( dirname( __FILE__ ) . '/views/html-retries-table.php' ); + include_once( dirname( __FILE__ ) . '/html-retries-table.php' ); do_action( 'woocommerce_subscriptions_retries_meta_box', $post->ID, $retries ); } diff --git a/includes/payment-retry/class-wcs-retry-admin.php b/includes/payment-retry/admin/class-wcs-retry-admin.php similarity index 100% rename from includes/payment-retry/class-wcs-retry-admin.php rename to includes/payment-retry/admin/class-wcs-retry-admin.php diff --git a/includes/admin/meta-boxes/views/html-retries-table.php b/includes/payment-retry/admin/html-retries-table.php similarity index 100% rename from includes/admin/meta-boxes/views/html-retries-table.php rename to includes/payment-retry/admin/html-retries-table.php diff --git a/includes/class-wcs-retry-manager.php b/includes/payment-retry/class-wcs-retry-manager.php similarity index 98% rename from includes/class-wcs-retry-manager.php rename to includes/payment-retry/class-wcs-retry-manager.php index 20bbc4d..4801305 100644 --- a/includes/class-wcs-retry-manager.php +++ b/includes/payment-retry/class-wcs-retry-manager.php @@ -274,14 +274,11 @@ class WCS_Retry_Manager { * When a retry hook is triggered, check if the rules for that retry are still valid * and if so, retry the payment. * - * @param WC_Order|int The order on which the payment failed - * @since 2.1 + * @since 2.1.0 + * @param WC_Order|int The order on which the payment failed. */ - public static function maybe_retry_payment( $last_order ) { - - if ( ! is_object( $last_order ) ) { - $last_order = wc_get_order( $last_order ); - } + public static function maybe_retry_payment( $order_id ) { + $last_order = ! is_object( $order_id ) ? wc_get_order( $order_id ) : $order_id; if ( false === $last_order ) { return; diff --git a/includes/abstracts/abstract-wcs-retry-store.php b/includes/payment-retry/data-stores/abstract-wcs-retry-store.php similarity index 100% rename from includes/abstracts/abstract-wcs-retry-store.php rename to includes/payment-retry/data-stores/abstract-wcs-retry-store.php diff --git a/includes/payment-retry/class-wcs-retry-database-store.php b/includes/payment-retry/data-stores/class-wcs-retry-database-store.php similarity index 100% rename from includes/payment-retry/class-wcs-retry-database-store.php rename to includes/payment-retry/data-stores/class-wcs-retry-database-store.php diff --git a/includes/payment-retry/class-wcs-retry-hybrid-store.php b/includes/payment-retry/data-stores/class-wcs-retry-hybrid-store.php similarity index 100% rename from includes/payment-retry/class-wcs-retry-hybrid-store.php rename to includes/payment-retry/data-stores/class-wcs-retry-hybrid-store.php diff --git a/includes/payment-retry/class-wcs-retry-post-store.php b/includes/payment-retry/data-stores/class-wcs-retry-post-store.php similarity index 100% rename from includes/payment-retry/class-wcs-retry-post-store.php rename to includes/payment-retry/data-stores/class-wcs-retry-post-store.php diff --git a/includes/payment-retry/class-wcs-retry-stores.php b/includes/payment-retry/data-stores/class-wcs-retry-stores.php similarity index 100% rename from includes/payment-retry/class-wcs-retry-stores.php rename to includes/payment-retry/data-stores/class-wcs-retry-stores.php diff --git a/includes/emails/class-wcs-email-customer-payment-retry.php b/includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php similarity index 97% rename from includes/emails/class-wcs-email-customer-payment-retry.php rename to includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php index 2db1b9a..22b6a48 100644 --- a/includes/emails/class-wcs-email-customer-payment-retry.php +++ b/includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php @@ -27,7 +27,7 @@ class WCS_Email_Customer_Payment_Retry extends WCS_Email_Customer_Renewal_Invoic $this->template_html = 'emails/customer-payment-retry.php'; $this->template_plain = 'emails/plain/customer-payment-retry.php'; - $this->template_base = plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/'; + $this->template_base = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ); $this->subject = __( 'Automatic payment failed for {order_number}, we will retry {retry_time}', 'woocommerce-subscriptions' ); $this->heading = __( 'Automatic payment failed for order {order_number}', 'woocommerce-subscriptions' ); diff --git a/includes/emails/class-wcs-email-payment-retry.php b/includes/payment-retry/emails/class-wcs-email-payment-retry.php similarity index 97% rename from includes/emails/class-wcs-email-payment-retry.php rename to includes/payment-retry/emails/class-wcs-email-payment-retry.php index 44ccc08..71722f4 100644 --- a/includes/emails/class-wcs-email-payment-retry.php +++ b/includes/payment-retry/emails/class-wcs-email-payment-retry.php @@ -31,7 +31,7 @@ class WCS_Email_Payment_Retry extends WC_Email_Failed_Order { $this->template_html = 'emails/admin-payment-retry.php'; $this->template_plain = 'emails/plain/admin-payment-retry.php'; - $this->template_base = plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/'; + $this->template_base = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ); // We want all the parent's methods, with none of its properties, so call its parent's constructor, rather than my parent constructor WC_Email::__construct(); diff --git a/includes/payment-retry/class-wcs-retry-email.php b/includes/payment-retry/emails/class-wcs-retry-email.php similarity index 100% rename from includes/payment-retry/class-wcs-retry-email.php rename to includes/payment-retry/emails/class-wcs-retry-email.php diff --git a/includes/class-wc-order-item-pending-switch.php b/includes/switching/class-wc-order-item-pending-switch.php similarity index 100% rename from includes/class-wc-order-item-pending-switch.php rename to includes/switching/class-wc-order-item-pending-switch.php diff --git a/includes/class-wc-subscriptions-switcher.php b/includes/switching/class-wc-subscriptions-switcher.php similarity index 94% rename from includes/class-wc-subscriptions-switcher.php rename to includes/switching/class-wc-subscriptions-switcher.php index 2a588f0..bc30b45 100644 --- a/includes/class-wc-subscriptions-switcher.php +++ b/includes/switching/class-wc-subscriptions-switcher.php @@ -36,7 +36,7 @@ class WC_Subscriptions_Switcher { add_filter( 'post_type_link', array( __CLASS__, 'add_switch_query_arg_post_link' ), 12, 2 ); // Add the settings to control whether Switching is enabled and how it will behave - add_filter( 'woocommerce_subscription_settings', array( __CLASS__, 'add_settings' ) ); + add_filter( 'woocommerce_subscription_settings', array( __CLASS__, 'add_settings' ), 15 ); // Render "wcs_switching_options" field add_action( 'woocommerce_admin_field_wcs_switching_options', __CLASS__ . '::switching_options_field_html' ); @@ -47,11 +47,22 @@ class WC_Subscriptions_Switcher { // We need to create subscriptions on checkout and want to do it after almost all other extensions have added their products/items/fees add_action( 'woocommerce_checkout_order_processed', array( __CLASS__, 'process_checkout' ), 50, 2 ); + // Same as above for WooCommerce Blocks. + add_action( 'woocommerce_store_api_checkout_order_processed', array( __CLASS__, 'process_checkout' ), 50, 1 ); + // When creating an order, add meta if it's for switching a subscription add_action( 'woocommerce_checkout_update_order_meta', array( __CLASS__, 'add_order_meta' ), 10, 2 ); - // Add a renewal orders section to the Related Orders meta box - add_action( 'woocommerce_subscriptions_related_orders_meta_box_rows', array( __CLASS__, 'switch_order_meta_box_rows' ), 10 ); + // Same as above for WooCommerce Blocks. + if ( class_exists( 'Automattic\WooCommerce\Blocks\Package' ) ) { + if ( version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '7.2.0', '>=' ) ) { + add_action( 'woocommerce_store_api_checkout_update_order_meta', array( __CLASS__, 'add_order_meta' ), 10, 1 ); + } elseif ( version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '6.3.0', '>=' ) ) { + add_action( 'woocommerce_blocks_checkout_update_order_meta', array( __CLASS__, 'add_order_meta' ), 10, 1 ); + } else { + add_action( '__experimental_woocommerce_blocks_checkout_update_order_meta', array( __CLASS__, 'add_order_meta' ), 10, 1 ); + } + } // Don't allow switching to the same product add_filter( 'woocommerce_add_to_cart_validation', array( __CLASS__, 'validate_switch_request' ), 10, 4 ); @@ -138,6 +149,10 @@ class WC_Subscriptions_Switcher { add_action( 'woocommerce_grant_product_download_permissions', array( __CLASS__, 'delay_granting_download_permissions' ), 9, 1 ); add_action( 'woocommerce_subscriptions_switch_completed', array( __CLASS__, 'grant_download_permissions' ), 9, 1 ); add_action( 'woocommerce_subscription_checkout_switch_order_processed', array( __CLASS__, 'log_switches' ) ); + add_filter( 'woocommerce_subscriptions_admin_related_orders_to_display', array( __CLASS__, 'display_switches_in_related_order_metabox' ), 10, 3 ); + + // Override the add to cart text when switch args are present. + add_filter( 'woocommerce_product_single_add_to_cart_text', array( __CLASS__, 'display_switch_add_to_cart_text' ), 10, 1 ); } /** @@ -147,7 +162,7 @@ class WC_Subscriptions_Switcher { */ public static function attach_dependant_hooks() { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { // For order items created as part of a switch, keep a record of the prorated amounts add_action( 'woocommerce_add_order_item_meta', array( __CLASS__, 'add_order_item_meta' ), 10, 3 ); @@ -370,8 +385,7 @@ class WC_Subscriptions_Switcher { */ public static function add_settings( $settings ) { - array_splice( $settings, 12, 0, array( - + $switching_settings = array( array( 'name' => __( 'Switching', 'woocommerce-subscriptions' ), 'type' => 'title', @@ -379,12 +393,10 @@ class WC_Subscriptions_Switcher { 'desc' => sprintf( __( 'Allow subscribers to switch (upgrade or downgrade) between different subscriptions. %1$sLearn more%2$s.', 'woocommerce-subscriptions' ), '', '' ), 'id' => WC_Subscriptions_Admin::$option_prefix . '_switch_settings', ), - array( 'type' => 'wcs_switching_options', 'id' => WC_Subscriptions_Admin::$option_prefix . '_allow_switching', ), - array( 'name' => __( 'Prorate Recurring Payment', 'woocommerce-subscriptions' ), 'desc' => __( 'When switching to a subscription with a different recurring payment or billing period, should the price paid for the existing billing period be prorated when switching to the new subscription?', 'woocommerce-subscriptions' ), @@ -402,7 +414,6 @@ class WC_Subscriptions_Switcher { ), 'desc_tip' => true, ), - array( 'name' => __( 'Prorate Sign up Fee', 'woocommerce-subscriptions' ), 'desc' => __( 'When switching to a subscription with a sign up fee, you can require the customer pay only the gap between the existing subscription\'s sign up fee and the new subscription\'s sign up fee (if any).', 'woocommerce-subscriptions' ), @@ -418,7 +429,6 @@ class WC_Subscriptions_Switcher { ), 'desc_tip' => true, ), - array( 'name' => __( 'Prorate Subscription Length', 'woocommerce-subscriptions' ), 'desc' => __( 'When switching to a subscription with a length, you can take into account the payments already completed by the customer when determining how many payments the subscriber needs to make for the new subscription.', 'woocommerce-subscriptions' ), @@ -434,7 +444,6 @@ class WC_Subscriptions_Switcher { ), 'desc_tip' => true, ), - array( 'name' => __( 'Switch Button Text', 'woocommerce-subscriptions' ), 'desc' => __( 'Customise the text displayed on the button next to the subscription on the subscriber\'s account page. The default is "Switch Subscription", but you may wish to change this to "Upgrade" or "Change Subscription".', 'woocommerce-subscriptions' ), @@ -445,12 +454,16 @@ class WC_Subscriptions_Switcher { 'type' => 'text', 'desc_tip' => true, ), - array( 'type' => 'sectionend', 'id' => WC_Subscriptions_Admin::$option_prefix . '_switch_settings', ), - ) ); + ); + + // Insert the switch settings in after the synchronisation section otherwise add them to the end. + if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Synchroniser::$setting_id . '_title', $switching_settings, 'multiple-settings', 'sectionend' ) ) { + $settings = array_merge( $settings, $switching_settings ); + } return $settings; } @@ -538,9 +551,11 @@ class WC_Subscriptions_Switcher { return; } - $switch_url = esc_url( self::get_switch_url( $item_id, $item, $subscription ) ); - $switch_text = get_option( WC_Subscriptions_Admin::$option_prefix . '_switch_button_text', __( 'Upgrade or Downgrade', 'woocommerce-subscriptions' ) ); - $switch_link = sprintf( '%s', $switch_url, $switch_text ); + $switch_url = esc_url( self::get_switch_url( $item_id, $item, $subscription ) ); + $switch_text = apply_filters( 'woocommerce_subscriptions_switch_link_text', get_option( WC_Subscriptions_Admin::$option_prefix . '_switch_button_text', __( 'Upgrade or Downgrade', 'woocommerce-subscriptions' ) ), $item_id, $item, $subscription ); + $switch_classes = apply_filters( 'woocommerce_subscriptions_switch_link_classes', array( 'wcs-switch-link', 'button' ), $item_id, $item, $subscription ); + + $switch_link = sprintf( '%s', $switch_url, implode( ' ', (array) $switch_classes ), $switch_text ); echo wp_kses( apply_filters( 'woocommerce_subscriptions_switch_link', $switch_link, $item_id, $item, $subscription ), array( 'a' => array( 'href' => array(), 'title' => array(), 'class' => array() ) ) ); // phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound } @@ -558,7 +573,7 @@ class WC_Subscriptions_Switcher { $subscription = wcs_get_subscription( $subscription ); } - $product = wc_get_product( $item['product_id'] ); + $product = wc_get_product( $item['product_id'] ); $parent_products = WC_Subscriptions_Product::get_visible_grouped_parent_product_ids( $product ); $additional_query_args = array(); @@ -569,7 +584,13 @@ class WC_Subscriptions_Switcher { $switch_url = get_permalink( $product->get_id() ); if ( ! empty( $_GET ) && is_product() ) { - $product_variations = $product->get_variation_attributes(); + $product_variations = array(); + + // Attributes in GET args are prefixed with attribute_ so to make sure we compare them correctly, apply the same prefix. + foreach ( $product->get_variation_attributes() as $attribute => $value ) { + $product_variations[ wcs_maybe_prefix_key( strtolower( $attribute ), 'attribute_' ) ] = $value; + } + $additional_query_args = array_intersect_key( $_GET, $product_variations ); } } @@ -757,11 +778,11 @@ class WC_Subscriptions_Switcher { * If the order being generated is for switching a subscription, keep a record of some of the switch * routines meta against the order. * - * @param int $order_id The ID of a WC_Order object - * @param array $posted The data posted on checkout + * @param int|\WC_Order $order_id The ID of a WC_Order object + * @param array $posted The data posted on checkout * @since 1.4 */ - public static function add_order_meta( $order_id, $posted ) { + public static function add_order_meta( $order_id, $posted = array() ) { $order = wc_get_order( $order_id ); @@ -789,7 +810,7 @@ class WC_Subscriptions_Switcher { */ public static function add_order_item_meta( $order_item_id, $cart_item, $cart_item_key ) { - if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( false === wcs_is_woocommerce_pre( '3.0' ) ) { _deprecated_function( __METHOD__, '2.2.0 and WooCommerce 3.0.0', __CLASS__ . '::add_order_line_item_meta( $order_item, $cart_item_key, $cart_item )' ); } @@ -840,7 +861,7 @@ class WC_Subscriptions_Switcher { if ( wcs_is_subscription( $order ) ) { if ( ! empty( $switch_details['item_id'] ) ) { - $order_item->add_meta_data( '_switched_subscription_item_id', $switch_details['item_id'] ); + $order_item->update_meta_data( '_switched_subscription_item_id', $switch_details['item_id'] ); } } else { $sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( '_subscription_sign_up_fee_prorated', true ); @@ -863,7 +884,7 @@ class WC_Subscriptions_Switcher { */ public static function set_subscription_item_meta( $item_id, $cart_item, $cart_item_key ) { - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { _deprecated_function( __METHOD__, '2.2.0', __CLASS__ . '::add_subscription_line_item_meta( $order_item, $cart_item_key, $cart_item )' ); } @@ -887,11 +908,12 @@ class WC_Subscriptions_Switcher { * If the item is on a new billing schedule and there are other items on the existing subscription, the old item will * be removed and the new item will be added to a new subscription by @see WC_Subscriptions_Checkout::process_checkout() * - * @param int $order_id The post_id of a shop_order post/WC_Order object - * @param array $posted_data The data posted on checkout + * @param int|\WC_Order $order_id The post_id of a shop_order post/WC_Order + * object + * @param array $posted_data The data posted on checkout * @since 2.0 */ - public static function process_checkout( $order_id, $posted_data ) { + public static function process_checkout( $order_id, $posted_data = array() ) { global $wpdb; if ( ! WC_Subscriptions_Cart::cart_contains_subscription() ) { @@ -937,7 +959,7 @@ class WC_Subscriptions_Switcher { if ( $is_single_item_subscription || ( false === $is_different_billing_schedule && false === $is_different_payment_date && false === $is_different_length ) ) { // Add the new item - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $item_id = WC_Subscriptions_Checkout::add_cart_item( $subscription, $cart_item, $cart_item_key ); wcs_update_order_item_type( $item_id, 'line_item_pending_switch', $subscription->get_id() ); } else { @@ -1084,7 +1106,7 @@ class WC_Subscriptions_Switcher { WC_Subscriptions_Checkout::add_shipping( $subscription, $recurring_cart ); - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { // We must save the subscription, we need the Shipping method saved // otherwise the ID is bogus (new:1) and we need it. $subscription->save(); @@ -1099,7 +1121,7 @@ class WC_Subscriptions_Switcher { } } - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $subscription->set_total( $subscription_shipping_total, 'shipping' ); } else { $subscription->set_shipping_total( $subscription_shipping_total ); @@ -1159,84 +1181,20 @@ class WC_Subscriptions_Switcher { /** * Updates address on the subscription if one of them is changed. * - * @param WC_Order $order The new order - * @param WC_Subscription $subscription The original subscription + * @param WC_Order $order The new order + * @param WC_Subscription $subscription The original subscription */ public static function maybe_update_subscription_address( $order, $subscription ) { - - if ( method_exists( $subscription, 'get_address' ) ) { - - $order_billing = $order->get_address( 'billing' ); - $order_shipping = $order->get_address(); - $subscription_billing = $subscription->get_address( 'billing' ); - $subscription_shipping = $subscription->get_address(); - - } else { - - $order_billing = wcs_get_order_address( $order, 'billing' ); - $order_shipping = wcs_get_order_address( $order ); - $subscription_billing = wcs_get_order_address( $subscription, 'billing' ); - $subscription_shipping = wcs_get_order_address( $subscription ); - - } - - $subscription->set_address( array_diff_assoc( $order_billing, $subscription_billing ), 'billing' ); - $subscription->set_address( array_diff_assoc( $order_shipping, $subscription_shipping ), 'shipping' ); - - } - - /** - * If the subscription purchased in an order has since been switched, include a link to the order placed to switch the subscription - * in the "Related Orders" meta box (displayed on the Edit Order screen). - * - * @param WC_Order $order The current order. - * @since 1.4 - */ - public static function switch_order_meta_box_rows( $post ) { - - $subscriptions = array(); - $switched_subscriptions = array(); - $orders = array(); - - // On the subscription page, just show related orders - if ( wcs_is_subscription( $post->ID ) ) { - - // Select the orders which switched item/s from this subscription - $orders = wcs_get_switch_orders_for_subscription( $post->ID ); - - foreach ( $orders as $order_id => $order ) { - wcs_set_objects_property( $order, 'relationship', __( 'Switch Order', 'woocommerce-subscriptions' ), 'set_prop_only' ); - } - - // Select the subscriptions which had item/s switched to this subscription by its parent order - if ( ! empty( $post->post_parent ) ) { - $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $post->post_parent ); - } - - // On the Edit Order screen, show any subscriptions with items switched by this order - } else { - $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $post->ID ); - } - - if ( is_array( $switched_subscriptions ) ) { - foreach ( $switched_subscriptions as $subscription_id => $subscription ) { - wcs_set_objects_property( $subscription, 'relationship', __( 'Switched Subscription', 'woocommerce-subscriptions' ), 'set_prop_only' ); - $orders[ $subscription_id ] = $subscription; - } - } - - foreach ( $orders as $order ) { - include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'includes/admin/meta-boxes/views/html-related-orders-row.php' ); - } - + $subscription->set_address( array_diff_assoc( $order->get_address( 'billing' ), $subscription->get_address( 'billing' ) ), 'billing' ); + $subscription->set_address( array_diff_assoc( $order->get_address( 'shipping' ), $subscription->get_address( 'shipping' ) ), 'shipping' ); } /** * Check if the cart includes any items which are to switch an existing subscription's contents. * - * @return bool|array Returns cart items that modify subscription contents, or false if no such items exist. * @since 2.0 * @param string $item_action Types of items to include ("any", "switch", or "add"). + * @return bool|array Returns cart items that modify subscription contents, or false if no such items exist. */ public static function cart_contains_switches( $item_action = 'switch' ) { $subscription_switches = false; @@ -1753,8 +1711,6 @@ class WC_Subscriptions_Switcher { * @since 2.1 */ public static function process_subscription_switches( $order_id, $order_old_status, $order_new_status ) { - global $wpdb; - $order = wc_get_order( $order_id ); $switch_processed = wcs_get_objects_property( $order, 'completed_subscription_switch' ); @@ -1767,16 +1723,17 @@ class WC_Subscriptions_Switcher { if ( $order_completed ) { try { // Start transaction if available - $wpdb->query( 'START TRANSACTION' ); + $transaction = new WCS_SQL_Transaction(); + $transaction->start(); self::complete_subscription_switches( $order ); wcs_set_objects_property( $order, 'completed_subscription_switch', 'true' ); - $wpdb->query( 'COMMIT' ); + $transaction->commit(); } catch ( Exception $e ) { - $wpdb->query( 'ROLLBACK' ); + $transaction->rollback(); throw $e; } @@ -1883,6 +1840,16 @@ class WC_Subscriptions_Switcher { return $product_subtotal; } + /** + * Gets the switch direction of a cart item. + * + * @param array $cart_item Cart item object. + * @return string|null Cart item subscription switch direction or null. + */ + public static function get_cart_item_switch_type( $cart_item ) { + return isset( $cart_item['subscription_switch'], $cart_item['subscription_switch']['upgraded_or_downgraded'] ) ? $cart_item['subscription_switch']['upgraded_or_downgraded'] : null; + } + /** * Creates a 2.0 updated version of the "subscriptions_switched" callback for developers to hook onto. * @@ -2101,7 +2068,7 @@ class WC_Subscriptions_Switcher { */ public static function set_force_payment_flag_in_cart( $total ) { - if ( $total > 0 || 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) || false === self::cart_contains_switches( 'any' ) ) { + if ( $total > 0 || wcs_is_manual_renewal_required() || false === self::cart_contains_switches( 'any' ) ) { return $total; } @@ -2178,7 +2145,7 @@ class WC_Subscriptions_Switcher { public static function maybe_set_payment_method_after_switch( $order ) { // Only set manual subscriptions to automatic if automatic payments are enabled - if ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) { + if ( wcs_is_manual_renewal_required() ) { return; } @@ -2239,13 +2206,14 @@ class WC_Subscriptions_Switcher { * @param WC_Subscription $subscription The Subscription. * @param WC_Order_Item $subscription_item The current line item on the subscription to map back through the related orders. * @param string $include_sign_up_fees Optional. Whether to include the sign-up fees paid. Can be 'include_sign_up_fees' or 'exclude_sign_up_fees'. Default 'include_sign_up_fees'. + * @param WC_Order[] $orders_to_include Optional. The orders to include in the total. * * @return float The total amount paid for an existing subscription line item. */ - public static function calculate_total_paid_since_last_order( $subscription, $subscription_item, $include_sign_up_fees = 'include_sign_up_fees' ) { + public static function calculate_total_paid_since_last_order( $subscription, $subscription_item, $include_sign_up_fees = 'include_sign_up_fees', $orders_to_include = array() ) { $found_item = false; $item_total_paid = 0; - $orders = $subscription->get_related_orders( 'all', array( 'parent', 'renewal', 'switch' ) ); + $orders = empty( $orders_to_include ) ? $subscription->get_related_orders( 'all', array( 'parent', 'renewal', 'switch' ) ) : $orders_to_include; // We need the orders sorted by the date they were paid, with the newest first. wcs_sort_objects( $orders, 'date_paid', 'descending' ); @@ -2334,6 +2302,46 @@ class WC_Subscriptions_Switcher { } } + /** + * Adds switch orders or switched subscriptions to the related order meta box. + * + * @since 3.1.0 + * + * @param WC_Abstract_Order[] $orders_to_display The list of related orders to display. + * @param WC_Subscription[] $subscriptions The list of related subscriptions. + * @param WP_Post $post The order or subscription post being viewed. + * + * @return $orders_to_display The orders/subscriptions to display in the meta box. + */ + public static function display_switches_in_related_order_metabox( $orders_to_display, $subscriptions, $post ) { + $switched_subscriptions = array(); + + // On the subscription page, just show related orders. + if ( wcs_is_subscription( $post->ID ) ) { + + foreach ( wcs_get_switch_orders_for_subscription( $post->ID ) as $order ) { + $order->update_meta_data( '_relationship', __( 'Switch Order', 'woocommerce-subscriptions' ) ); + $orders_to_display[] = $order; + } + + // Display the subscriptions which had item/s switched to this subscription by its parent order. + if ( ! empty( $post->post_parent ) ) { + $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $post->post_parent ); + } + + // On the Edit Order screen, show any subscriptions with items switched by this order. + } else { + $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $post->ID ); + } + + foreach ( $switched_subscriptions as $subscription ) { + $subscription->update_meta_data( '_relationship', __( 'Switched Subscription', 'woocommerce-subscriptions' ) ); + $orders_to_display[] = $subscription; + } + + return $orders_to_display; + } + /** Deprecated Methods **/ /** @@ -2535,6 +2543,22 @@ class WC_Subscriptions_Switcher { return $cart_contains_subscription_creating_switch; } + /** + * Filters the add to cart text for products during a switch request. + * + * @since 3.1.0 + * + * @param string $add_to_cart_text The product's default add to cart text. + * @return string 'Switch subscription' during a switch, or the default add to cart text if switch args aren't present. + */ + public static function display_switch_add_to_cart_text( $add_to_cart_text ) { + if ( isset( $_GET['switch-subscription'], $_GET['item'] ) ) { + $add_to_cart_text = _x( 'Switch subscription', 'add to cart button text while switching a subscription', 'woocommerce-subscriptions' ); + } + + return $add_to_cart_text; + } + /** * Don't allow switched subscriptions to be cancelled. * @@ -2827,4 +2851,51 @@ class WC_Subscriptions_Switcher { return $related_orders; } + + /** + * If the subscription purchased in an order has since been switched, include a link to the order placed to switch the subscription + * in the "Related Orders" meta box (displayed on the Edit Order screen). + * + * @param WC_Order $order The current order. + * @since 1.4 + * @deprecated 3.1.0 + */ + public static function switch_order_meta_box_rows( $post ) { + wcs_deprecated_function( __METHOD__, '3.1.0' ); + $subscriptions = array(); + $switched_subscriptions = array(); + $orders = array(); + + // On the subscription page, just show related orders + if ( wcs_is_subscription( $post->ID ) ) { + + // Select the orders which switched item/s from this subscription + $orders = wcs_get_switch_orders_for_subscription( $post->ID ); + + foreach ( $orders as $order_id => $order ) { + wcs_set_objects_property( $order, 'relationship', __( 'Switch Order', 'woocommerce-subscriptions' ), 'set_prop_only' ); + } + + // Select the subscriptions which had item/s switched to this subscription by its parent order + if ( ! empty( $post->post_parent ) ) { + $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $post->post_parent ); + } + + // On the Edit Order screen, show any subscriptions with items switched by this order + } else { + $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $post->ID ); + } + + if ( is_array( $switched_subscriptions ) ) { + foreach ( $switched_subscriptions as $subscription_id => $subscription ) { + wcs_set_objects_property( $subscription, 'relationship', __( 'Switched Subscription', 'woocommerce-subscriptions' ), 'set_prop_only' ); + $orders[ $subscription_id ] = $subscription; + } + } + + foreach ( $orders as $order ) { + include( WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'includes/admin/meta-boxes/views/html-related-orders-row.php' ) ); + } + + } } diff --git a/includes/class-wcs-add-cart-item.php b/includes/switching/class-wcs-add-cart-item.php similarity index 84% rename from includes/class-wcs-add-cart-item.php rename to includes/switching/class-wcs-add-cart-item.php index cb6685f..38ac8c0 100644 --- a/includes/class-wcs-add-cart-item.php +++ b/includes/switching/class-wcs-add-cart-item.php @@ -57,6 +57,17 @@ class WCS_Add_Cart_Item extends WCS_Switch_Cart_Item { return 0; } + /** + * Determines if the last order was a switch and the outcome of that was a fully reduced pre-paid term. + * Since the last order didn't contain this item, we can safely return false here. + * + * @since 3.0.7 + * @return bool Whether the last order was a switch and it fully reduced the prepaid term. + */ + protected function is_switch_after_fully_reduced_prepaid_term() { + return false; + } + /** Helper functions */ /** diff --git a/includes/class-wcs-cart-switch.php b/includes/switching/class-wcs-cart-switch.php similarity index 82% rename from includes/class-wcs-cart-switch.php rename to includes/switching/class-wcs-cart-switch.php index 2c01292..07ddebc 100644 --- a/includes/class-wcs-cart-switch.php +++ b/includes/switching/class-wcs-cart-switch.php @@ -25,6 +25,9 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal { // Check if a user is requesting to pay for a switch order, needs to happen after $wp->query_vars are set add_action( 'template_redirect', array( &$this, 'maybe_setup_cart' ), 99 ); + + // Filters the Place order button text + add_filter( 'woocommerce_order_button_text', array( $this, 'order_button_text' ), 15 ); } /** @@ -38,6 +41,7 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal { // Remove version dependent callbacks which don't apply to switch carts remove_filter( 'woocommerce_checkout_update_customer_data', array( &$this, 'maybe_update_subscription_customer_data' ), 10 ); remove_filter( 'woocommerce_checkout_update_user_meta', array( &$this, 'maybe_update_subscription_address_data' ), 10 ); + remove_filter( 'woocommerce_store_api_checkout_update_customer_from_request', array( &$this, 'maybe_update_subscription_address_data_from_store_api' ), 10, 2 ); } /** @@ -101,7 +105,7 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal { // Backwards compatibility (2.1 -> 2.1.2) $subscription_item_id_key = ( isset( $switch_data['switches'][ $item_id ]['subscription_item_id'] ) ) ? 'subscription_item_id' : 'remove_line_item'; - $_GET['item'] = $switch_data['switches'][ $item_id ][ $subscription_item_id_key ]; + $_GET['item'] = $switch_data['switches'][ $item_id ][ $subscription_item_id_key ]; break; } } @@ -121,7 +125,7 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal { $meta_value = is_array( $meta_value ) ? $meta_value[0] : $meta_value; // In WC 3.0 the meta values are no longer arrays if ( taxonomy_is_product_attribute( $meta_key ) || meta_is_product_attribute( $meta_key, $meta_value, $product_id ) ) { - $variations[ $meta_key ] = $meta_value; + $variations[ $meta_key ] = $meta_value; $_POST[ 'attribute_' . $meta_key ] = $meta_value; } } @@ -134,9 +138,7 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal { } } - WC()->session->set( 'order_awaiting_payment', $order_id ); - $this->set_cart_hash( $order_id ); - + $this->set_order_awaiting_payment( $order_id ); wp_safe_redirect( wc_get_checkout_url() ); exit; } @@ -162,4 +164,22 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal { } } } + + /** + * Overrides the place order button text on the checkout when the cart contains only switch requests. + * + * @since 3.1.0 + * + * @param string $place_order_text The place order button text. + * @return string The place order button text. 'Switch subscription' if the cart contains only switches, otherwise the default. + */ + public function order_button_text( $place_order_text ) { + $cart_switches = WC_Subscriptions_Switcher::cart_contains_switches(); + + if ( isset( WC()->cart ) && $cart_switches && count( $cart_switches ) === count( WC()->cart->get_cart() ) ) { + $place_order_text = _x( 'Switch subscription', 'The place order button text while switching a subscription', 'woocommerce-subscriptions' ); + } + + return $place_order_text; + } } diff --git a/includes/class-wcs-switch-cart-item.php b/includes/switching/class-wcs-switch-cart-item.php similarity index 75% rename from includes/class-wcs-switch-cart-item.php rename to includes/switching/class-wcs-switch-cart-item.php index 599687f..471a1ce 100644 --- a/includes/class-wcs-switch-cart-item.php +++ b/includes/switching/class-wcs-switch-cart-item.php @@ -255,8 +255,14 @@ class WCS_Switch_Cart_Item { * @return float */ public function get_total_paid_for_current_period() { + if ( ! isset( $this->total_paid_for_current_period ) ) { - $this->total_paid_for_current_period = WC_Subscriptions_Switcher::calculate_total_paid_since_last_order( $this->subscription, $this->existing_item, 'exclude_sign_up_fees' ); + // If the last order was a switch with a fully reduced pre-paid term, the amount the cutomer has paid is just the total in that order. + if ( $this->is_switch_after_fully_reduced_prepaid_term() ) { + $this->total_paid_for_current_period = WC_Subscriptions_Switcher::calculate_total_paid_since_last_order( $this->subscription, $this->existing_item, 'exclude_sign_up_fees', array( $this->get_last_switch_order() ) ); + } else { + $this->total_paid_for_current_period = WC_Subscriptions_Switcher::calculate_total_paid_since_last_order( $this->subscription, $this->existing_item, 'exclude_sign_up_fees' ); + } } return $this->total_paid_for_current_period; @@ -334,9 +340,16 @@ class WCS_Switch_Cart_Item { $method_to_use = 'days_in_billing_cycle'; } + // If the last order was a switch order with a fully reduced pre-paid term. + if ( $this->is_switch_after_fully_reduced_prepaid_term() ) { + $method_to_use = 'days_between_switch_and_next_payment'; + } + // Find the number of days between the last payment and the next if ( 'days_between_payments' === $method_to_use ) { $days_in_old_cycle = round( ( $this->next_payment_timestamp - $this->get_last_order_paid_time() ) / DAY_IN_SECONDS ); + } elseif ( 'days_between_switch_and_next_payment' === $method_to_use ) { + $days_in_old_cycle = round( ( $this->next_payment_timestamp - $this->get_last_switch_order()->get_date_paid()->getTimestamp() ) / DAY_IN_SECONDS ); } else { $days_in_old_cycle = wcs_get_days_in_cycle( $this->subscription->get_billing_period(), $this->subscription->get_billing_interval() ); } @@ -351,7 +364,12 @@ class WCS_Switch_Cart_Item { * @return int */ public function calculate_days_in_new_cycle() { - $last_order_time = $this->get_last_order_paid_time(); + if ( $this->is_switch_after_fully_reduced_prepaid_term() ) { + $last_order_time = $this->get_last_switch_order()->get_date_paid()->getTimestamp(); + } else { + $last_order_time = $this->get_last_order_paid_time(); + } + $new_billing_period = WC_Subscriptions_Product::get_period( $this->product ); $new_billing_interval = WC_Subscriptions_Product::get_interval( $this->product ); @@ -411,4 +429,79 @@ class WCS_Switch_Cart_Item { public function is_switch_during_trial() { return $this->subscription->get_time( 'trial_end' ) > gmdate( 'U' ); } + + /** + * Retrieves the subscription's last switch order. + * + * @since 3.0.7 + * @return WC_Order|Null The last switch order or null if one doesn't exist. + */ + protected function get_last_switch_order() { + static $switch_order = null; + + if ( ! $switch_order ) { + $switch_order = $this->subscription->get_last_order( 'all', 'switch' ); + } + + return $switch_order; + } + + /** + * Determines if the last order was a switch and the outcome of that was a fully reduced pre-paid term. + * + * A fully reduced pre-paid term occurs when the amount the customer has paid (in total including switches) doesn't cover the amount of time that has elapsed already at the new price per day. + * + * For example: + * - Original purchase of a $70 / week subscription. + * - 5 days into the subscription the customer switches to a $120 / 3 days. The lower freqency triggers the pre-paid term to be reduced. + * - The $70 paid at $40 a day only entitles the customer to 1.75 days. + * - Because they are already 5 days into the subscription, that $70 is fully absorbed at the new price and no time is 'owed'. + * - The subscription starts today and the customer pays full price. + * + * @see https://docs.woocommerce.com/document/subscriptions/switching-guide/#section-11 + * @see WCS_Switch_Totals_Calculator::reduce_prepaid_term() + * + * @since 3.0.7 + * @return bool Whether the last order was a switch and it fully reduced the prepaid term. + */ + protected function is_switch_after_fully_reduced_prepaid_term() { + + if ( ! isset( $this->is_switch_after_fully_reduced_prepaid_term ) ) { + $last_switch_order = $this->get_last_switch_order(); + + if ( empty( $last_switch_order ) || ! $last_switch_order->get_date_paid() ) { + $this->is_switch_after_fully_reduced_prepaid_term = false; + return false; + } + + $switch_paid_date = $last_switch_order->get_date_paid(); + + // If the last switch order occured after the last payment order (parent or renewal) + if ( $switch_paid_date->getTimestamp() < $this->get_last_order_paid_time() ) { + $this->is_switch_after_fully_reduced_prepaid_term = false; + return false; + } + + /** + * If the last switch resulted in the customer being charged the pull cost upfront, the customer must have been entitled to fewer days than had already elapsed - see reduce_prepaid_term(). + * This means the subscription billing term would have started from that switch order's date, not the last order (parent/renewal) date. + */ + $first_payment_after_switch = WC_Subscriptions_Product::get_first_renewal_payment_time( $this->existing_item->get_product(), gmdate( 'Y-m-d H:i:s', $switch_paid_date->format( 'U' ) ) ); + + // If the first payment date after the last switch is roughly equal (+- 1 hour) to the next payment date, then it was a fully reduced pre-paid term switch. + $this->is_switch_after_fully_reduced_prepaid_term = ( $this->next_payment_timestamp - HOUR_IN_SECONDS <= $first_payment_after_switch ) && ( $first_payment_after_switch <= $this->next_payment_timestamp + HOUR_IN_SECONDS ); + } + + return $this->is_switch_after_fully_reduced_prepaid_term; + } + + /** + * Determines whether the customer is switching to a subscription with a length of 1 - one off payment. + * + * @since 3.0.12 + * @return bool + */ + public function is_switch_to_one_payment_subscription() { + return 1 === absint( WC_Subscriptions_Product::get_length( $this->product ) ); + } } diff --git a/includes/class-wcs-switch-totals-calculator.php b/includes/switching/class-wcs-switch-totals-calculator.php old mode 100644 new mode 100755 similarity index 88% rename from includes/class-wcs-switch-totals-calculator.php rename to includes/switching/class-wcs-switch-totals-calculator.php index 36eee1b..dd948b7 --- a/includes/class-wcs-switch-totals-calculator.php +++ b/includes/switching/class-wcs-switch-totals-calculator.php @@ -97,7 +97,9 @@ class WCS_Switch_Totals_Calculator { $this->set_switch_type_in_cart( $cart_item_key, $switch_type ); if ( $this->should_prorate_recurring_price( $switch_item ) ) { - if ( 'upgrade' === $switch_type ) { + + // Switching to a product with only 1 payment means no next payment can be collected and so we calculate a gap payment in that scenario. + if ( 'upgrade' === $switch_type || $switch_item->is_switch_to_one_payment_subscription() ) { if ( $this->should_reduce_prepaid_term( $switch_item ) ) { $this->reduce_prepaid_term( $cart_item_key, $switch_item ); } else { @@ -107,7 +109,9 @@ class WCS_Switch_Totals_Calculator { $upgrade_cost = $this->calculate_upgrade_cost( $switch_item ); $this->set_upgrade_cost( $switch_item, $upgrade_cost ); } - } elseif ( 'downgrade' === $switch_type && $this->should_extend_prepaid_term() ) { + } + + if ( apply_filters( 'wcs_switch_should_extend_prepaid_term', 'downgrade' === $switch_type && $this->should_extend_prepaid_term(), $switch_item ) ) { $this->extend_prepaid_term( $cart_item_key, $switch_item ); } @@ -121,6 +125,8 @@ class WCS_Switch_Totals_Calculator { $this->apportion_length( $switch_item ); } + do_action( 'wcs_switch_calculations_completed', $switch_item, $cart_item_key ); + if ( defined( 'WCS_DEBUG' ) && WCS_DEBUG && ! wcs_doing_ajax() ) { $this->log_switch( $switch_item ); } @@ -210,7 +216,7 @@ class WCS_Switch_Totals_Calculator { $prorate_all = in_array( $this->apportion_recurring_price, array( 'yes', 'yes-upgrade' ) ); $prorate_virtual = in_array( $this->apportion_recurring_price, array( 'virtual', 'virtual-upgrade' ) ); - return $prorate_all || ( $prorate_virtual && $switch_item->is_virtual_product() ); + return apply_filters( 'wcs_switch_should_prorate_recurring_price', $prorate_all || ( $prorate_virtual && $switch_item->is_virtual_product() ), $switch_item ); } /** @@ -265,7 +271,8 @@ class WCS_Switch_Totals_Calculator { * @return bool */ protected function should_apportion_length( $switch_item ) { - return 'yes' == $this->apportion_length || ( 'virtual' == $this->apportion_length && $switch_item->is_virtual_product() ); + + return apply_filters( 'wcs_switch_should_prorate_length', 'yes' == $this->apportion_length || ( 'virtual' == $this->apportion_length && $switch_item->is_virtual_product() ), $switch_item ); } /** Total Calculators */ @@ -279,9 +286,9 @@ class WCS_Switch_Totals_Calculator { * @param WCS_Switch_Cart_Item $switch_item */ protected function apportion_sign_up_fees( $switch_item ) { - if ( 'no' === $this->apportion_sign_up_fee ) { - $switch_item->product->update_meta_data( '_subscription_sign_up_fee', 0 ); - } elseif ( $switch_item->existing_item && 'yes' === $this->apportion_sign_up_fee ) { + $should_apportion_sign_up_fee = apply_filters( 'wcs_switch_should_prorate_sign_up_fee', 'yes' === $this->apportion_sign_up_fee, $switch_item ); + + if ( $should_apportion_sign_up_fee && $switch_item->existing_item ) { $product = wc_get_product( $switch_item->canonical_product_id ); // Make sure we get a fresh copy of the product's meta to avoid prorating an already prorated sign-up fee @@ -296,8 +303,16 @@ class WCS_Switch_Totals_Calculator { $sign_up_fee_paid = ( $sign_up_fee_paid * $switch_item->existing_item['qty'] ) / $switch_item->cart_item['quantity']; } - $switch_item->product->update_meta_data( '_subscription_sign_up_fee', max( $sign_up_fee_due - $sign_up_fee_paid, 0 ) ); + // Allowing third parties to customize the applied sign-up fee + $subscription_sign_up_fee = apply_filters( 'wcs_switch_sign_up_fee', max( $sign_up_fee_due - $sign_up_fee_paid, 0 ), $switch_item ); + + $switch_item->product->update_meta_data( '_subscription_sign_up_fee', $subscription_sign_up_fee ); $switch_item->product->update_meta_data( '_subscription_sign_up_fee_prorated', WC_Subscriptions_Product::get_sign_up_fee( $switch_item->product ) ); + } elseif ( 'no' === $this->apportion_sign_up_fee ) { + // Allowing third parties to force the application of a sign-up fee + $subscription_sign_up_fee = apply_filters( 'wcs_switch_sign_up_fee', 0, $switch_item ); + + $switch_item->product->update_meta_data( '_subscription_sign_up_fee', $subscription_sign_up_fee ); } } @@ -379,7 +394,12 @@ class WCS_Switch_Totals_Calculator { // Find how many more days at the new lower price it takes to exceed the amount owed $days_to_add = $this->calculate_pre_paid_days( $amount_still_owing, $switch_item->get_new_price_per_day() ); - $days_to_add -= $switch_item->get_days_until_next_payment(); + // Subtract days until next payments only if days to add is not zero + if ( 0 !== $days_to_add ) { + $days_to_add -= $switch_item->get_days_until_next_payment(); + } + + $days_to_add = apply_filters( 'wcs_switch_days_to_extend_prepaid_term', $days_to_add, $cart_item_key, $switch_item ); $this->cart->cart_contents[ $cart_item_key ]['subscription_switch']['first_payment_timestamp'] = $switch_item->next_payment_timestamp + ( $days_to_add * DAY_IN_SECONDS ); } @@ -391,7 +411,17 @@ class WCS_Switch_Totals_Calculator { * @param WCS_Switch_Cart_Item $switch_item */ protected function apportion_length( $switch_item ) { - $base_length = WC_Subscriptions_Product::get_length( $switch_item->canonical_product_id ); + $base_length = wcs_get_objects_property( $switch_item->product, 'subscription_base_length_prorated' ); + + // Already modified the subscription length of this instance previously? + if ( is_null( $base_length ) ) { + // Get the length from the unmodified product instance, and save it for later. + // A "lazier" way to do the same would have been to call 'WC_Subscriptions_Product::get_length( $switch_item->canonical_product_id )', but this breaks APFS, and is more expensive performance-wise. + // See https://github.com/woocommerce/woocommerce-subscriptions/issues/3928 + $base_length = WC_Subscriptions_Product::get_length( $switch_item->product ); + wcs_set_objects_property( $switch_item->product, 'subscription_base_length_prorated', $base_length, 'set_prop_only' ); + } + $completed_payments = $switch_item->subscription->get_payment_count(); $length_remaining = $base_length - $completed_payments; @@ -400,6 +430,8 @@ class WCS_Switch_Totals_Calculator { $length_remaining = $base_length; } + $length_remaining = apply_filters( 'wcs_switch_length_remaining', $length_remaining, $switch_item ); + $switch_item->product->update_meta_data( '_subscription_length', $length_remaining ); } diff --git a/languages/woocommerce-subscriptions-fr.mo b/languages/woocommerce-subscriptions-fr.mo new file mode 100644 index 0000000..d7c119a Binary files /dev/null and b/languages/woocommerce-subscriptions-fr.mo differ diff --git a/languages/woocommerce-subscriptions-fr.po b/languages/woocommerce-subscriptions-fr.po new file mode 100644 index 0000000..a4694f5 --- /dev/null +++ b/languages/woocommerce-subscriptions-fr.po @@ -0,0 +1,8189 @@ +# Translation of WooCommerce - WooCommerce Subscriptions in French (France) +# This file is distributed under the same license as the WooCommerce - WooCommerce Subscriptions package. +msgid "" +msgstr "" +"PO-Revision-Date: 2020-11-06 17:52:37+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: GlotPress/2.4.0-alpha\n" +"Language: fr\n" +"Project-Id-Version: WooCommerce - WooCommerce Subscriptions\n" + +#: includes/class-wc-subscriptions-order.php:517 +msgid "Payment completed on order after subscription was cancelled." +msgstr "" + +#. Translators: Placeholder is the subscription ID number. +#: includes/class-wc-subscriptions-manager.php:917 +msgid "" +"The related subscription #%s has been deleted after the customer was deleted." +msgstr "" + +#. Translators: 1: The subscription ID number. 2: The current user's username. +#: includes/class-wc-subscriptions-manager.php:914 +msgid "" +"The related subscription #%1$s has been deleted after the customer was " +"deleted by %2$s." +msgstr "" + +#: templates/checkout/recurring-totals.php:19 +msgid "Recurring totals" +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: includes/class-wc-subscriptions-checkout.php:569 +msgid "" +"Purchasing a subscription product requires an account. Please go to the %sMy " +"Account%s page to login or contact us if you need assistance." +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: includes/class-wc-subscriptions-checkout.php:566 +msgid "" +"Purchasing a subscription product requires an account. Please go to the %sMy " +"Account%s page to login or register." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:384 +msgid "Lock manual price increases" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:380 +msgid "" +"This order contains line items with prices above the current product price. " +"To override the product's live price when the customer pays for this order, " +"lock in the manual price increases." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:124 +msgid "Please enter a date at least 2 minutes into the future." +msgstr "" + +#: templates/myaccount/subscription-details.php:62 +msgid "Using the auto-renewal toggle is disabled while in staging mode." +msgstr "" +"L’utilisation de la bascule de renouvellement automatique est désactivée en " +"mode préproduction." + +#: templates/myaccount/subscription-details.php:24 +msgctxt "customer subscription table header" +msgid "Start date" +msgstr "Date de début" + +#: templates/myaccount/related-orders.php:15 +msgid "Related orders" +msgstr "Commandes similaires" + +#: templates/myaccount/my-subscriptions.php:77 +msgid "Browse products" +msgstr "Parcourir les produits" + +#: templates/myaccount/my-subscriptions.php:74 +msgid "You have no active subscriptions." +msgstr "Vous n’avez pas d’abonnement actif." + +#: templates/html-early-renewal-modal-content.php:34 +msgid "Want to renew early via the checkout? Click %shere.%s" +msgstr "" +"Vous voulez renouveler tôt via la validation de commande ? Cliquez %sici.%s" + +#: templates/html-early-renewal-modal-content.php:28 +msgid "" +"By renewing your subscription early, your scheduled next payment on %s will " +"be cancelled." +msgstr "" +"En renouvelant votre abonnement tôt, votre prochain paiement planifié le %s " +"sera annulé." + +#: templates/html-early-renewal-modal-content.php:23 +msgid "By renewing your subscription early your next payment will be %s." +msgstr "En renouvelant votre abonnement tôt, votre prochain paiement sera %s." + +#. Translators: Placeholders are opening and closing My Account link tags. +#: templates/emails/subscription-info.php:57 +msgid "" +"This subscription is set to renew automatically using your payment method on " +"file. You can manage or cancel this subscription from your %smy account " +"page%s." +msgid_plural "" +"These subscriptions are set to renew automatically using your payment method " +"on file. You can manage or cancel your subscriptions from your %smy account " +"page%s." +msgstr[0] "" +"Cet abonnement est configuré pour se renouveler automatiquement en utilisant " +"votre moyen de paiement enregistré. Vous pouvez gérer ou annuler cet " +"abonnement sur votre %spage Mon compte%s." +msgstr[1] "" +"Ces abonnements sont configurés pour se renouveler automatiquement en " +"utilisant votre moyen de paiement enregistré. Vous pouvez gérer ou annuler " +"vos abonnements sur votre %spage Mon compte%s." + +#: templates/emails/subscription-info.php:37 +msgctxt "Used as end date for an indefinite subscription" +msgid "When cancelled" +msgstr "En cas d’annulation" + +#: templates/emails/subscription-info.php:28 +msgctxt "table heading" +msgid "Recurring total" +msgstr "Total récurrent" + +#: templates/emails/subscription-info.php:27 +msgctxt "table heading" +msgid "End date" +msgstr "Date de fin" + +#: templates/emails/subscription-info.php:26 +msgctxt "table heading" +msgid "Start date" +msgstr "Date de début" + +#: templates/emails/subscription-info.php:25 +msgctxt "subscription ID table heading" +msgid "ID" +msgstr "ID" + +#. Translators: Placeholder is the My Account URL. +#: templates/emails/plain/subscription-info.php:51 +msgid "" +"This subscription is set to renew automatically using your payment method on " +"file. You can manage or cancel this subscription from your my account page. " +"%s" +msgid_plural "" +"These subscriptions are set to renew automatically using your payment method " +"on file. You can manage or cancel your subscriptions from your my account " +"page. %s" +msgstr[0] "" +"Cet abonnement est configuré pour se renouveler automatiquement en utilisant " +"votre moyen de paiement enregistré. Vous pouvez gérer ou annuler cet " +"abonnement sur votre page Mon compte. %s" +msgstr[1] "" +"Ces abonnements sont configurés pour se renouveler automatiquement en " +"utilisant votre moyen de paiement enregistré. Vous pouvez gérer ou annuler " +"vos abonnements sur votre page Mon compte. %s" + +#: templates/emails/plain/subscription-info.php:38 +#: templates/emails/subscription-info.php:42 +msgid "Next payment: %s" +msgstr "Paiement suivant : %s" + +#. translators: placeholder is either view or edit url for the subscription +#: templates/emails/plain/subscription-info.php:27 +msgctxt "in plain emails for subscription information" +msgid "View subscription: %s" +msgstr "Afficher l’abonnement : %s" + +#: templates/emails/email-order-details.php:61 +msgid "Note:" +msgstr "Remarque :" + +#. translators: %s: Order number +#: templates/emails/customer-processing-renewal-order.php:19 +#: templates/emails/plain/customer-processing-renewal-order.php:18 +msgid "" +"Just to let you know — we've received your subscription renewal order " +"#%s, and it is now being processed:" +msgstr "" +"Pour information – nous avons reçu votre commande de renouvellement " +"d’abonnement n° %s, elle est maintenant en cours de traitement :" + +#: templates/emails/customer-on-hold-renewal-order.php:18 +#: templates/emails/plain/customer-on-hold-renewal-order.php:17 +msgid "" +"Thanks for your renewal order. It’s on-hold until we confirm that payment " +"has been received. In the meantime, here’s a reminder of your order:" +msgstr "" +"Merci pour votre commande de renouvellement. Elle est en attente jusqu’à ce " +"que nous confirmions que le paiement ait bien été reçu. En attendant, voici " +"un rappel de votre commande :" + +#: templates/emails/customer-completed-renewal-order.php:18 +#: templates/emails/plain/customer-completed-renewal-order.php:17 +msgid "We have finished processing your subscription renewal order." +msgstr "" +"Nous avons terminé de traiter votre commande de renouvellement d’abonnement." + +#. translators: %s: Customer first name +#: templates/emails/customer-completed-renewal-order.php:17 +#: templates/emails/customer-completed-switch-order.php:17 +#: templates/emails/customer-on-hold-renewal-order.php:17 +#: templates/emails/customer-payment-retry.php:16 +#: templates/emails/customer-processing-renewal-order.php:17 +#: templates/emails/customer-renewal-invoice.php:16 +#: templates/emails/plain/customer-completed-renewal-order.php:16 +#: templates/emails/plain/customer-completed-switch-order.php:16 +#: templates/emails/plain/customer-on-hold-renewal-order.php:16 +#: templates/emails/plain/customer-payment-retry.php:16 +#: templates/emails/plain/customer-processing-renewal-order.php:16 +#: templates/emails/plain/customer-renewal-invoice.php:16 +msgid "Hi %s," +msgstr "Salut %s," + +#. translators: 1) passed sort order type argument, 2) 'ascending', 3) +#. 'descending'. +#: includes/wcs-helper-functions.php:266 +msgid "" +"Invalid sort order type: %1$s. The $sort_order argument must be %2$s or %3$s." +msgstr "" +"Type d’ordre de tri non valide : %1$s. L’argument $sort_order doit être %2$s " +"ou %3$s." + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/templates/update-welcome-notice.php:16 +msgid "Want to know more about Subscriptions %s?" +msgstr "Vous désirez en savoir plus sur Subscriptions %s ?" + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:99 +msgid "Welcome to WooCommerce Subscriptions %s!" +msgstr "Bienvenue dans WooCommerce Subscriptions %s !" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:92 +msgid "" +"Previous versions of Subscriptions relied on %1$sWP Cron%2$s to process " +"subscription payments and other scheduled events. In 3.0, these events will " +"now run on admin request with loopback support. This will significantly " +"increase the throughput of payment processing." +msgstr "" +"Les versions précédentes de Subscriptions reposaient sur %1$sWP Cron%2$s " +"pour traiter les paiements d’abonnements et d’autres événements planifiés. " +"Dans la version 3.0, ces événements s’exécuteront désormais à la demande de " +"l’administrateur avec prise en charge du bouclage. Cela augmentera " +"considérablement le débit du traitement des paiements." + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:89 +msgid "Increased processing rate for scheduled payments" +msgstr "Augmentation du taux de traitement des paiements planifiés" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:86 +msgid "" +"Scheduled action data, which was previously stored in the WordPress post " +"tables, has been moved to a custom database table. Amongst other benefits, " +"this will greatly improve the performance of processing scheduled actions " +"such as subscription payments." +msgstr "" +"Les données des actions planifiées, qui étaient auparavant stockées dans les " +"tables d’articles WordPress, ont été déplacées dans une table de base de " +"données personnalisée. Entre autres avantages, cela améliorera " +"considérablement les performances du traitement des actions planifiées " +"telles que les paiements d’abonnement." + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:85 +msgid "Improved scheduled action data storage" +msgstr "Stockage amélioré des données des actions planifiées" + +#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:29 +msgid "" +"To resolve this as quickly as possible, please create a %1$stemporary " +"administrator account%3$s with the user email woologin@woocommerce.com and " +"share the credentials with us via %2$sQuickForget.com%3$s." +msgstr "" +"Pour résoudre ceci le plus rapidement possible, veuillez créer un %1$scompte " +"d’administrateur temporaire%3$s avec l’adresse e-mail d’utilisateur " +"woologin@woocommerce.com et partager les identifiants de connexion avec nous " +"via %2$sQuickForget.com%3$s." + +#. translators: opening/closing tags - links to documentation. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:126 +msgid "" +"%1$sPayPal Reference Transactions are not enabled on your account%2$s. If " +"you wish to use PayPal Reference Transactions with Subscriptions, please " +"contact PayPal and request they %3$senable PayPal Reference Transactions%4$s " +"on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" +"%1$sPayPal Reference Transactions n’est pas activé sur votre compte%2$s. Si " +"vous souhaitez utiliser PayPal Reference Transactions avec Subscriptions, " +"veuillez contacter PayPal et leur demander d’%3$sactiver PayPal Reference " +"Transactions%4$s sur votre compte. %5$sVérifier le compte PayPal%6$s %3$sEn " +"savoir plus%7$s" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:135 +msgid "" +"Sorry, it seems there are no available payment methods which support " +"subscriptions. Please see %1$sEnabling Payment Gateways for " +"Subscriptions%2$s if you require assistance." +msgstr "" +"Désolé, il semble qu’aucun mode de paiement ne soit disponible pour les " +"abonnements. Veuillez consulter %1$sActiver des passerelles de paiement pour " +"Subscriptions%2$s si vous avez besoin d’aide." + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:26 +msgid "Thank you for your renewal order" +msgstr "Merci pour votre commande de renouvellement" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:25 +msgid "Your {blogname} renewal order has been received!" +msgstr "Votre commande de renouvellement de {blogname} a été reçue !" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:24 +msgid "" +"This is an order notification sent to customers containing order details " +"after a renewal order is placed on-hold." +msgstr "" +"Ceci est une notification de commande envoyée aux clients après qu’une " +"commande de renouvellement est placée en attente et contenant les détails de " +"la commande." + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:23 +msgid "On-hold Renewal Order" +msgstr "Commande de renouvellement en attente" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:153 +msgid "Your early renewal order was successful." +msgstr "Votre commande de renouvellement anticipé a réussi." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:145 +msgid "" +"Payment for the renewal order was unsuccessful with your payment method on " +"file, please try again." +msgstr "" +"Le paiement de la commande de renouvellement a échoué avec votre moyen de " +"paiement enregistré, veuillez réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:128 +msgid "" +"We couldn't create a renewal order for your subscription, please try again." +msgstr "" +"Nous n’avons pas pu créer de commande de renouvellement pour votre " +"abonnement, veuillez réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:118 +msgid "You can't renew the subscription at this time. Please try again." +msgstr "" +"Vous ne pouvez pas renouveler l’abonnement pour le moment. Veuillez " +"réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:113 +msgid "We were unable to locate that subscription, please try again." +msgstr "Nous n’avons pas pu localiser cet abonnement, veuillez réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:56 +msgid "Renew early" +msgstr "Renouveler tôt" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:39 +msgid "Pay now" +msgstr "Payer maintenant" + +#. translators: 1-2: opening/closing tags , 2-3: opening/closing tags +#. for a link to docs on early renewal. +#: includes/early-renewal/class-wcs-early-renewal-manager.php:66 +msgid "" +"Allow customers to bypass the checkout and renew their subscription early " +"from their %1$sMy Account > View Subscription%2$s page. %3$sLearn more.%4$s" +msgstr "" +"Autorisez les clients à contourner la validation de commande et à renouveler " +"leur abonnement tôt sur la page %1$sMon compte > Afficher l’abonnement%2$s. " +"%3$sEn savoir plus.%4$s" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:63 +msgid "Accept Early Renewal Payments via a Modal" +msgstr "Accepter les paiements de renouvellement anticipé via un modal" + +#: includes/class-wcs-switch-totals-calculator.php:196 +msgid "" +"Your cart contained an invalid subscription switch request. It has been " +"removed from your cart." +msgstr "" +"Votre panier contenait une demande de changement d’abonnement non valide. " +"Elle a été supprimée de votre panier." + +#. translators: placeholder is a payment method title. +#: includes/class-wcs-staging.php:97 +msgid "" +"Subscription locked to Manual Renewal while the store is in staging mode. " +"Live payment method: %s" +msgstr "" +"Abonnement verrouillé sur Renouvellement manuel pendant que la boutique est " +"en mode préproduction. Moyen de paiement en direct : %s" + +#: includes/class-wcs-staging.php:83 +msgid "" +"Subscription locked to Manual Renewal while the store is in staging mode. " +"Payment method changes will take effect in live mode." +msgstr "" +"Abonnement verrouillé sur Renouvellement manuel pendant que la boutique est " +"en mode préproduction. Les changements de moyen de paiement prendront effet " +"en mode en direct." + +#. translators: %s is order's number +#: includes/class-wcs-cart-renewal.php:330 +msgid "Order #%s has not been added to the cart." +msgstr "La commande n°%s n’a pas été ajoutée au panier." + +#. translators: %s: new item name. +#: includes/class-wc-subscriptions-switcher.php:1988 +msgctxt "used in order notes" +msgid "Customer added %s." +msgstr "Le client a ajouté %s." + +#: includes/class-wc-subscriptions-manager.php:134 +msgid "Manual renewal order awaiting customer payment." +msgstr "Commande de renouvellement manuel en attente de paiement client." + +#. translators: %1$s is the coupon code, %2$d is the number of payment usages +#: includes/class-wc-subscriptions-coupon.php:1047 +msgid "" +"Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d " +"time." +msgid_plural "" +"Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d " +"times." +msgstr[0] "" +"Le code de promotion à usage limité « %1$s » a été supprimé de l’abonnement. " +"Il a été utilisé %2$d fois." +msgstr[1] "" +"Le code de promotion à usage limité « %1$s » a été supprimé de l’abonnement. " +"Il a été utilisé %2$d fois." + +#: includes/class-wc-subscriptions-cart-validator.php:111 +msgid "" +"Your cart has been emptied of subscription products. Only one subscription " +"product can be purchased at a time." +msgstr "" +"Des produits d’abonnement ont été retirés de votre panier. Un seul produit " +"d’abonnement peut être acheté à la fois." + +#: includes/class-wc-product-subscription.php:73 +msgid "Read more" +msgstr "Lire plus" + +#: includes/api/class-wc-rest-subscriptions-controller.php:691 +msgid "Meta value." +msgstr "Valeur de la méta." + +#: includes/api/class-wc-rest-subscriptions-controller.php:685 +msgid "Meta label." +msgstr "Etiquette de la méta." + +#: includes/api/class-wc-rest-subscriptions-controller.php:679 +msgid "Meta key." +msgstr "Clé de la méta." + +#: includes/api/class-wc-rest-subscriptions-controller.php:671 +msgid "Removed line item meta data." +msgstr "Métadonnées de l'article de la ligne supprimées." + +#: includes/api/class-wc-rest-subscriptions-controller.php:662 +msgid "Tax subtotal." +msgstr "Sous-total de la TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:656 +msgid "Tax total." +msgstr "Total de la TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:650 +msgid "Tax rate ID." +msgstr "ID du taux de TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:642 +msgid "Line taxes." +msgstr "Ligne de TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:637 +msgid "Line total tax (after discounts)." +msgstr "Ligne de total de TVA (après remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:632 +msgid "Line total (after discounts)." +msgstr "Ligne de total (après remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:627 +msgid "Line subtotal tax (before discounts)." +msgstr "Ligne de sous-total de TVA (avant remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:622 +msgid "Line subtotal (before discounts)." +msgstr "Ligne de sous-total (avant remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:616 +msgid "Product price." +msgstr "Tarif du produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:610 +msgid "Tax class of product." +msgstr "Classe de TVA de produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:605 +msgid "Quantity ordered." +msgstr "Quantité commandé." + +#: includes/api/class-wc-rest-subscriptions-controller.php:600 +msgid "Variation ID, if applicable." +msgstr "ID de la variation, si applicable." + +#: includes/api/class-wc-rest-subscriptions-controller.php:595 +msgid "Product ID." +msgstr "ID produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:589 +msgid "Product SKU." +msgstr "UGS du produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:583 +msgid "Product name." +msgstr "Nom du produit" + +#: includes/api/class-wc-rest-subscriptions-controller.php:577 +msgid "Item ID." +msgstr "ID de l’article." + +#: includes/api/class-wc-rest-subscriptions-controller.php:570 +msgid "Removed line items data." +msgstr "Données articles de la ligne supprimées." + +#: includes/api/class-wc-rest-subscriptions-controller.php:497 +msgid "" +"The status to transition the subscription to. Unlike the \"status\" param, " +"this will calculate and update the subscription dates." +msgstr "" +"État vers lequel effectuer la transition de l’abonnement. Contrairement au " +"paramètre « état », cela calculera et mettra à jour les dates d’abonnement." + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:97 +msgid "" +"The number of upcoming renewal orders, for currently active subscriptions." +msgstr "" +"Nombre de commandes de renouvellement à venir, pour les abonnements " +"actuellement actifs." + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:90 +msgid "" +"The sum of all the upcoming renewal orders, including items, fees, tax and " +"shipping, for currently active subscriptions." +msgstr "" +"Somme de toutes les commandes de renouvellement à venir, incluant les " +"articles, les frais, les frais d’expédition et de taxe, pour les abonnements " +"actuellement actifs." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:1024 +msgid "Switch Totals" +msgstr "Totaux de changements" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:678 +msgid "%2$s %1$s current subscriptions" +msgstr "%2$s %1$s abonnements actuels" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:653 +msgid "%2$s %1$s ended subscriptions" +msgstr "%2$s %1$s abonnements terminés" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:631 +msgid "%2$s %1$s subscription cancellations" +msgstr "%2$s %1$s annulations d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:609 +msgid "%2$s %1$s subscription switches" +msgstr "%2$s %1$s changements d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:587 +msgid "%2$s %1$s subscription renewals" +msgstr "%2$s %1$s renouvellements d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:565 +msgid "%2$s %1$s subscription resubscribes" +msgstr "%2$s %1$s réabonnements d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:543 +msgid "%2$s %1$s subscription signups" +msgstr "%2$s %1$s inscriptions d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:521 +msgid "%2$s %1$s new subscriptions" +msgstr "%2$s %1$s nouveaux abonnements" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:513 +msgid "The sum of all switch orders including tax and shipping." +msgstr "" +"Somme de toutes les commandes de changement, incluant les frais d’expédition " +"et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:512 +msgid "%s switch revenue in this period" +msgstr "%s revenu de changement sur cette période" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:232 +msgid "Copy billing address" +msgstr "Copier l’adresse de facturation" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 +msgid "Billing" +msgstr "Facturation" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:69 +msgid "Profile →" +msgstr "Profil →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:64 +msgid "View other subscriptions →" +msgstr "Afficher les autres abonnements →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:52 +msgid "General" +msgstr "Général" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:102 +msgctxt "relation to order" +msgid "Unknown Order Type" +msgstr "Type de commande inconnu" + +#: includes/admin/class-wcs-wc-admin-manager.php:59 +msgid "Edit Subscription" +msgstr "Modifier l’abonnement" + +#: includes/admin/class-wcs-wc-admin-manager.php:49 +msgid "Add New" +msgstr "Ajouter" + +#: includes/admin/class-wcs-admin-meta-boxes.php:284 +msgid "Retry renewal payment action requested by admin." +msgstr "" +"Réessayez l’action de paiement de renouvellement demandée par " +"l’administrateur." + +#. translators: Placeholders are opening and closing link tags. +#: includes/admin/class-wc-subscriptions-admin.php:1541 +msgid "" +"We weren't able to locate the set of report results you requested. Please " +"regenerate the link from the %1$sSubscription Reports screen%2$s." +msgstr "" +"Nous n’avons pas pu localiser l’ensemble de résultats de rapport que vous " +"avez demandé. Veuillez régénérer le lien sur l’%1$sécran Rapports " +"d’abonnement%2$s." + +#: wcs-functions.php:130 +msgctxt "Error message while creating a subscription" +msgid "" +"Invalid created date. The date must be a string and of the format: \"Y-m-d H:" +"i:s\"." +msgstr "" + +#: templates/checkout/form-change-payment-method.php:49 +msgctxt "text on button on checkout page" +msgid "Add payment method" +msgstr "" + +#. translators: placeholder is a localized date and time (e.g. "February 1, +#. 2018 10:20 PM") +#: includes/wcs-formatting-functions.php:251 +msgctxt "wcs_get_human_time_diff" +msgid "%s" +msgstr "" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:80 +msgctxt "plugin version number used in admin notice" +msgid "3.0" +msgstr "" + +#: includes/class-wcs-retry-manager.php:268 +msgctxt "used in order note as reason for why status changed" +msgid "Retry rule reapplied:" +msgstr "" + +#. translators: 1: previous token, 2: new token. +#: includes/class-wcs-my-account-payment-methods.php:199 +msgctxt "used in subscription note" +msgid "" +"Payment method meta updated after customer changed their default token and " +"opted to update their subscriptions. Payment meta changed from %1$s to %2$s" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:234 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (charge the full recurring amount at sign-up)" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:233 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (do not charge any recurring amount)" +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:150 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:198 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Customer requested to renew early:" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:711 +#: includes/class-wc-subscriptions-change-payment-gateway.php:752 +msgctxt "the page title of the add payment method form" +msgid "Add payment method" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:279 +msgctxt "label on button, imperative" +msgid "Add payment" +msgstr "" + +#. translators: %s: address type (eg. 'billing' or 'shipping'). +#: includes/class-wc-subscriptions-addresses.php:213 +msgctxt "change billing or shipping address" +msgid "Change %s address" +msgstr "" + +#. translators: %s: parent order number (linked to its details screen). +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:387 +msgctxt "subscription note after linking to a parent order" +msgid "Subscription linked to parent order %s via admin." +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribe Order" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:204 +msgctxt "label for the system status page" +msgid "Retries Migration Status" +msgstr "État des nouvelles tentatives de migration" + +#: includes/payment-retry/class-wcs-retry-admin.php:196 +msgctxt "label for the system status page" +msgid "Custom Retry Rule" +msgstr "Règle de nouvelle tentative personnalisée" + +#: includes/payment-retry/class-wcs-retry-admin.php:188 +msgctxt "label for the system status page" +msgid "Custom Raw Retry Rule" +msgstr "Règle de nouvelle tentative brute personnalisée" + +#: includes/payment-retry/class-wcs-retry-admin.php:180 +msgctxt "label for the system status page" +msgid "Custom Retry Rule Class" +msgstr "Classe de règle de nouvelle tentative personnalisée" + +#: includes/payment-retry/class-wcs-retry-admin.php:172 +msgctxt "label for the system status page" +msgid "Custom Retry Rules" +msgstr "Règles de nouvelle tentative personnalisées" + +#: includes/admin/class-wcs-admin-system-status.php:357 +msgctxt "label for the system status page" +msgid "Country / State" +msgstr "Pays / État" + +#: includes/admin/class-wcs-admin-system-status.php:329 +msgctxt "label for the system status page" +msgid "PayPal Reference Transactions Enabled" +msgstr "PayPal Reference Transactions activé" + +#: includes/admin/class-wcs-admin-system-status.php:295 +msgctxt "label for the system status page" +msgid "Other" +msgstr "Autre" + +#: includes/admin/class-wcs-admin-system-status.php:265 +msgctxt "label for the system status page" +msgid "Active Product Key" +msgstr "Clé de produit active" + +#: includes/admin/class-wcs-admin-system-status.php:242 +msgctxt "label for the system status page" +msgid "WooCommerce Account Connected" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:221 +msgctxt "label for the system status page" +msgid "Subscription Statuses" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:119 +msgctxt "Live URL, Label on WooCommerce -> System Status page" +msgid "Subscriptions Live URL" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:75 +msgctxt "meta box title" +msgid "Schedule" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:243 +msgctxt "there's a number immediately in front of this text" +msgid "days prior to Renewal Day" +msgstr "" + +#. Author URI of the plugin +msgid "https://woocommerce.com/" +msgstr "https://woocommerce.com/" + +#. translators: 1$-2$: opening and closing tags. 3$-4$: opening and +#. closing link tags for learn more. Leads to duplicate site article on docs. +#. 5$-6$: Opening and closing link to production URL. 7$: Production URL . +#: woocommerce-subscriptions.php:930 +msgid "" +"It looks like this site has moved or is a duplicate site. %1$sWooCommerce " +"Subscriptions%2$s has disabled automatic payments and subscription related " +"emails on this site to prevent duplicate payments from a staging or test " +"environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be " +"the site's URL. %3$sLearn more »%4$s." +msgstr "" +"Il semble que ce site a été déplacé ou est un site dupliqué. %1$sWooCommerce " +"Subscriptions%2$s a désactivé des paiements automatiques et les e-mails liés " +"aux abonnements sur ce site pour éviter les paiements en double à partir " +"d’un environnement de préproduction ou de test. %1$sWooCommerce " +"Subscriptions%2$s pense que %5$s%7$s%6$s est l’URL du site. %3$sEn savoir " +"plus »%4$s." + +#: woocommerce-subscriptions.php:861 +msgid "Installed Plugins" +msgstr "Extensions installées" + +#. translators: 1-2: opening/closing tags, 3: Subscriptions version. +#: woocommerce-subscriptions.php:858 +msgid "" +"%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early " +"Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce " +"Subscriptions%2$s comes with that plugin's functionality packaged into the " +"core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to " +"avoid any conflicts." +msgstr "" +"%1$sAttention !%2$sNous pouvons voir que l’extension %1$sWooCommerce " +"Subscriptions Early Renewal%2$s est active. La version %3$s de " +"%1$sWooCommerce Subscriptions%2$s est fournie avec la fonctionnalité de " +"cette extension intégrée à l’extension principale. Veuillez désactiver " +"WooCommerce Subscriptions Early Renewal pour éviter tout conflit." + +#: woocommerce-subscriptions.php:393 +msgid "Would you like to add a payment method now?" +msgstr "Voulez-vous ajouter un moyen de paiement maintenant ?" + +#: woocommerce-subscriptions.php:393 +msgid "" +"To enable automatic renewals for this subscription, you will first need to " +"add a payment method." +msgstr "" +"Pour activer les renouvellements automatiques pour cet abonnement, vous " +"devez d’abord ajouter un moyen de paiement." + +#: templates/single-product/add-to-cart/variable-subscription.php:34 +msgid "You have added a variation of this product to the cart already." +msgstr "Vous avez déjà ajouté une variante de ce produit au panier." + +#: templates/myaccount/subscription-details.php:71 +msgid "Payment" +msgstr "Paiement" + +#: templates/myaccount/subscription-details.php:57 +msgid "Disable auto renew" +msgstr "Désactiver le renouvellement automatique" + +#: templates/myaccount/subscription-details.php:50 +msgid "Enable auto renew" +msgstr "Activer le renouvellement automatique" + +#: templates/myaccount/subscription-details.php:42 +msgid "Auto renew" +msgstr "Renouvellement automatique" + +#: templates/myaccount/my-subscriptions.php:72 +msgid "You have reached the end of subscriptions. Go to the %sfirst page%s." +msgstr "" +"Vous avez atteint la fin des abonnements. Allez à la %spremière page%s." + +#: templates/myaccount/my-subscriptions.php:65 +msgid "Next" +msgstr "Suivant" + +#: templates/myaccount/my-subscriptions.php:61 +msgid "Previous" +msgstr "Précédent" + +#. translators: $1: opening tag, $2: closing tag +#: templates/checkout/form-change-payment-method.php:91 +msgid "" +"Update the payment method used for %1$sall%2$s of my current subscriptions" +msgstr "" +"Mettre à jour le moyen de paiement utilisé pour %1$stous%2$s mes abonnements " +"actuels" + +#. translators: $1 the log file name $2 and $3 are opening and closing link +#. tags, respectively. +#: templates/admin/html-failed-scheduled-action-notice.php:38 +msgid "" +"To see further details about these errors, view the %1$s log file from the " +"%2$sWooCommerce logs screen.%2$s" +msgstr "" +"Pour voir plus de détails sur ces erreurs, consultez le fichier journal %1$s " +"sur l’%2$sécran des journaux de WooCommerce.%2$s" + +#: templates/admin/html-failed-scheduled-action-notice.php:31 +msgid "Affected event:" +msgid_plural "Affected events:" +msgstr[0] "Événement affecté :" +msgstr[1] "Événements affectés :" + +#: templates/admin/html-failed-scheduled-action-notice.php:21 +msgid "" +"An error has occurred while processing a recent subscription related event. " +"For steps on how to fix the affected subscription and to learn more about " +"the possible causes of this error, please read our guide %1$shere%2$s." +msgid_plural "" +"An error has occurred while processing recent subscription related events. " +"For steps on how to fix the affected subscriptions and to learn more about " +"the possible causes of this error, please read our guide %1$shere%2$s." +msgstr[0] "" +"Une erreur est survenue lors du traitement d’un événement récent lié à un " +"abonnement. Pour savoir comment résoudre l’abonnement affecté et en savoir " +"plus sur les causes possibles de cette erreur, veuillez lire notre guide " +"%1$sici%2$s." +msgstr[1] "" +"Une erreur est survenue lors du traitement d’événements récents liés à un " +"abonnement. Pour savoir comment résoudre les abonnements affectés et en " +"savoir plus sur les causes possibles de cette erreur, veuillez lire notre " +"guide %1$sici%2$s." + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/wcs-formatting-functions.php:243 +msgid "in %s" +msgstr "dans %s" + +#: includes/wcs-cart-functions.php:252 +msgid "[Remove]" +msgstr "[Enlever]" + +#: includes/upgrades/templates/update-welcome-notice.php:8 +msgid "What's new?" +msgstr "Qu’est-ce qui change ?" + +#. translators: placeholder $1 is the Subscription version string ('2.3'), $2-3 +#. are opening and closing tags +#: includes/upgrades/templates/update-welcome-notice.php:5 +msgid "" +"Version %1$s brings some new improvements requested by store managers just " +"like you (and possibly even by %2$syou%3$s)." +msgstr "" +"La version %1$s apporte de nouvelles améliorations demandées par des gérants " +"de boutique comme vous (et peut-être même par %2$svous%3$s)." + +#: includes/upgrades/class-wcs-repair-suspended-paypal-subscriptions.php:51 +msgid "" +"Subscription suspended by Database repair script. This subscription was " +"suspended via PayPal." +msgstr "" +"Abonnement suspendu par le script de réparation de base de données. Cet " +"abonnement a été suspendu via PayPal." + +#. translators: 1-2: opening/closing tags, 3-4: opening/closing tags +#. linked to ticket form. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:895 +msgid "" +"%1$sWarning!%2$s We discovered an issue in %1$sWooCommerce Subscriptions 2.3." +"0 - 2.3.2%2$s that may cause your subscription renewal order and customer " +"subscription caches to contain invalid data. For information about how to " +"update the cached data, please %3$sopen a new support ticket%4$s." +msgstr "" +"%1$sAttention !%2$s Nous avons découvert un problème dans %1$sWooCommerce " +"Subscriptions 2.3.0 - 2.3.2%2$s qui peut entraîner la présence de données " +"non valides dans votre commande de renouvellement d’abonnement et les caches " +"d’abonnements client. Pour plus d’informations sur la mise à jour des " +"données mises en cache, veuillez %3$souvrir un nouveau ticket " +"d’assistance%4$s." + +#. translators: 1-2: opening/closing tags, 3: active version of +#. Subscriptions, 4: current version of Subscriptions, 5-6: opening/closing +#. tags linked to ticket form, 7-8: opening/closing tags linked to +#. documentation. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:822 +msgid "" +"%1$sWarning!%2$s It appears that you have downgraded %1$sWooCommerce " +"Subscriptions%2$s from %3$s to %4$s. Downgrading the plugin in this way may " +"cause issues. Please update to %3$s or higher, or %5$sopen a new support " +"ticket%6$s for further assistance. %7$sLearn more »%8$s" +msgstr "" +"%1$sAttention !%2$s Il semble que vous avez rétrogradé %1$sWooCommerce " +"Subscriptions%2$s de %3$s à %4$s. Rétrograder l’extension de cette manière " +"peut causer des problèmes. Veuillez mettre à jour vers %3$s ou supérieur ou " +"bien %5$souvrir un nouveau ticket d’assistance%6$s pour obtenir une " +"assistance supplémentaire. %7$sEn savoir plus »%8$s" + +#: includes/privacy/class-wcs-privacy.php:277 +msgid "Customers with a subscription are excluded from this setting." +msgstr "Les clients avec un abonnement sont exclus de ce paramètre." + +#: includes/privacy/class-wcs-privacy.php:233 +msgid "" +"Retain ended subscriptions and their related orders for a specified duration " +"before anonymizing the personal data within them." +msgstr "" +"Conservez les abonnements terminés et leurs commandes liées pour la durée " +"spécifiée avant l’anonymisation des données personnelles." + +#: includes/privacy/class-wcs-privacy.php:232 +msgid "Retain ended subscriptions" +msgstr "Conserver les abonnements terminés" + +#. Translators: %s URL to erasure request screen. +#: includes/privacy/class-wcs-privacy.php:223 +msgid "" +"When handling an %s, should personal data within subscriptions be retained " +"or removed?" +msgstr "" +"Lors du traitement d’une %s, les données personnelles dans les abonnements " +"doivent-elles être conservées ou supprimées ?" + +#: includes/privacy/class-wcs-privacy.php:221 +msgid "Remove personal data from subscriptions" +msgstr "Supprimer les données personnelles des abonnements" + +#: includes/privacy/class-wcs-privacy.php:215 +msgid "account erasure request" +msgstr "demande d’effacement de données" + +#. translators: placeholders are opening and closing tags. +#: includes/privacy/class-wcs-privacy.php:195 +msgid "" +"%1$sNote:%2$s Orders which are related to subscriptions will not be included " +"in the orders affected by these settings." +msgstr "" +"%1$sRemarque :%2$s les commandes liées à des abonnements ne seront pas " +"incluses dans les commandes affectées par ces paramètres." + +#. translators: %d: number of subscriptions affected. +#: includes/privacy/class-wcs-privacy.php:176 +msgid "Removed personal data from %d subscription." +msgid_plural "Removed personal data from %d subscriptions." +msgstr[0] "Données personnelles supprimées de %d abonnement." +msgstr[1] "Données personnelles supprimées de %d abonnements." + +#: includes/privacy/class-wcs-privacy.php:109 +msgid "Cancel and remove personal data" +msgstr "Annuler et supprimer les données personnelles" + +#. translators: placeholders are opening and closing link tags, linking to +#. additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:99 +msgid "" +"If you are using PayPal Standard or PayPal Reference transactions please see " +"the %1$sPayPal Privacy Policy%2$s for more details." +msgstr "" +"Si vous utilisez PayPal Standard ou PayPal Reference Transactions, veuillez " +"consulter la %1$sPolitique de confidentialité de PayPal%2$s pour plus de " +"détails." + +#: includes/privacy/class-wcs-privacy.php:97 +msgid "" +"What personal information your store shares with external sources depends on " +"which third-party payment processor plugins you are using to collect " +"subscription payments. We recommend that you consult with their privacy " +"policies to inform this section of your privacy policy." +msgstr "" +"Les informations personnelles que votre boutique partage avec des sources " +"externes dépendent des extensions de plateforme de paiement tierces que vous " +"utilisez pour collecter les paiements d’abonnement. Nous vous recommandons " +"de consulter leurs politiques de confidentialité pour informer cette section " +"de votre politique de confidentialité." + +#: includes/privacy/class-wcs-privacy.php:96 +msgid "What we share with others" +msgstr "Ce que nous partageons avec d’autres" + +#. translators: placeholders are opening and closing link tags, linking to +#. additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:95 +msgid "" +"For the purposes of processing recurring subscription payments, we store the " +"customer's name, billing address, shipping address, email address, phone " +"number and credit card/payment details." +msgstr "" +"À des fins de traitement des paiements d’abonnement récurrents, nous " +"stockons le nom du client, son adresse de facturation, son adresse de " +"livraison, son adresse e-mail, son numéro de téléphone et ses détails de " +"carte de crédit/paiement." + +#. translators: placeholders are opening and closing link tags, linking to +#. additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:94 +msgid "What we collect and store" +msgstr "Ce que nous collectons et stockons" + +#: includes/privacy/class-wcs-privacy.php:92 +msgid "" +"By using WooCommerce Subscriptions, you may be storing personal data and " +"depending on which third-party payment processors you’re using to take " +"subscription payments, you may be sharing personal data with external " +"sources." +msgstr "" +"En utilisant WooCommerce Subscriptions, il est possible que vous stockiez " +"des données personnelles et, en fonction des plateformes de paiement tierces " +"que vous utilisez pour accepter les paiements d’abonnement, il est possible " +"que vous partagiez des données personnelles avec des sources externes." + +#: includes/privacy/class-wcs-privacy.php:43 +#: includes/privacy/class-wcs-privacy.php:44 +msgid "Subscriptions Data" +msgstr "Données des abonnements" + +#: includes/privacy/class-wcs-privacy-exporters.php:86 +msgid "Email Address" +msgstr "Adresse e-mail" + +#: includes/privacy/class-wcs-privacy-exporters.php:85 +msgid "Phone Number" +msgstr "Numéro de téléphone" + +#: includes/privacy/class-wcs-privacy-exporters.php:82 +msgid "Browser User Agent" +msgstr "Agent utilisateur du navigateur" + +#: includes/privacy/class-wcs-privacy-exporters.php:81 +msgid "IP Address" +msgstr "Addresse IP" + +#: includes/privacy/class-wcs-privacy-exporters.php:80 +msgid "Subscription Items" +msgstr "Articles d’abonnement" + +#: includes/privacy/class-wcs-privacy-exporters.php:78 +msgid "Created Date" +msgstr "Date de création" + +#: includes/privacy/class-wcs-privacy-erasers.php:189 +msgid "Personal data removed." +msgstr "Données personnelles supprimées." + +#. Translators: %s subscription number. +#: includes/privacy/class-wcs-privacy-erasers.php:75 +msgid "Personal data within subscription %s has been retained." +msgstr "Les données personnelles de l’abonnement %s ont été conservées." + +#. Translators: %s subscription number. +#: includes/privacy/class-wcs-privacy-erasers.php:71 +msgid "Removed personal data from subscription %s." +msgstr "Données personnelles supprimées de l’abonnement %s." + +#. translators: $1 is the log file name. $2 and $3 are opening and closing link +#. tags, respectively. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:46 +msgid "" +"To see the full error, view the %1$s log file from the %2$sWooCommerce logs " +"screen.%3$s." +msgstr "" +"Pour voir l’erreur complète, consultez le fichier journal %1$s sur " +"l’%2$sécran des journaux de WooCommerce%3$s." + +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:36 +msgid "Last recorded error:" +msgstr "Dernière erreur enregistrée :" + +#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:18 +msgid "" +"A fatal error has occurred while processing a recent subscription payment " +"with PayPal. Please %1$sopen a new ticket at WooCommerce Support%3$s " +"immediately to get this resolved. %2$sLearn more »%3$s" +msgstr "" +"Une erreur fatale est survenue lors du traitement d’un paiement d’abonnement " +"récent avec PayPal. Veuillez immédiatement %1$souvrir un nouveau ticket sur " +"WooCommerce Support%3$s pour résoudre cette erreur. %2$sEn savoir plus " +"»%3$s" + +#. translators: Placeholders are the opening and closing link tags. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:320 +msgid "" +"Before enabling PayPal Standard for Subscriptions, please note, when using " +"PayPal Standard, customers are locked into using PayPal Standard for the " +"life of their subscription, and PayPal Standard has a number of limitations. " +"Please read the guide on %1$swhy we don't recommend PayPal Standard%2$s for " +"Subscriptions before choosing to enable this option." +msgstr "" +"Avant d’activer PayPal Standard pour Subscriptions, veuillez noter que, " +"lorsque PayPal Standard est utilisé, les clients sont obligés d’utiliser " +"PayPal Standard pendant toute la durée de leur abonnement, et PayPal " +"Standard présente un certain nombre de limites. Veuillez lire le guide sur " +"%1$sla raison pour laquelle nous ne recommandons pas PayPal Standard%2$s " +"pour Subscriptions avant de choisir d’activer cette option." + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:312 +msgid "Enable PayPal Standard for Subscriptions" +msgstr "Activer PayPal Standard pour Subscriptions" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:199 +msgid "Open a ticket" +msgstr "Ouvrir un ticket" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:279 +msgid "Change payment features:" +msgstr "Modifier des fonctionnalités de paiement :" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:275 +msgid "Subscription features:" +msgstr "Fonctionnalités d’abonnement :" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:272 +msgid "Supported features:" +msgstr "Fonctionnalités prises en charge :" + +#. translators: %s: default e-mail heading. +#: includes/emails/class-wcs-email-cancelled-subscription.php:168 +msgid "" +"This controls the main heading contained within the email notification. " +"Leave blank to use the default heading: %s." +msgstr "" +"Cela contrôle l’en-tête principal contenu dans la notification par e-mail. " +"Laisser vide pour utiliser l’en-tête par défaut : %s." + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:55 +msgid "" +"With early renewals enabled, customers can renew their subscriptions before " +"the next payment date." +msgstr "" +"Lorsque les renouvellements anticipés sont activés, les clients peuvent " +"renouveler leurs abonnements avant la date du prochain paiement." + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:54 +msgid "Accept Early Renewal Payments" +msgstr "Accepter les paiements de renouvellement anticipé" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:53 +msgid "Early Renewal" +msgstr "Renouvellement anticipé" + +#. translators: %s: order ID (linked to details page). +#: includes/early-renewal/class-wcs-cart-early-renewal.php:312 +msgid "Order %s created to record early renewal." +msgstr "Commande %s créée pour enregistrer le renouvellement anticipé." + +#. translators: placeholder contains a link to the order's edit screen. +#: includes/early-renewal/wcs-early-renewal-functions.php:172 +msgid "" +"Failed to update subscription dates after customer renewed early with order " +"%s." +msgstr "" +"Échec de la mise à jour des dates d’abonnement après le renouvellement " +"anticipé du client avec la commande %s." + +#. translators: placeholder contains a link to the order's edit screen. +#: includes/early-renewal/wcs-early-renewal-functions.php:169 +msgid "Customer successfully renewed early with order %s." +msgstr "Le client a réussi le renouvellement anticipé avec la commande %s." + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:105 +msgid "Complete checkout to renew now." +msgstr "Terminez la validation de commande pour renouveler maintenant." + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:99 +msgid "" +"You can not renew this subscription early. Please contact us if you need " +"assistance." +msgstr "" +"Vous ne pouvez pas renouveler cet abonnement de manière anticipée. Contactez-" +"nous si vous avez besoin d’aide." + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:71 +msgid "Renew now" +msgstr "Renouveler maintenant" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "" +"This will clear the persistent cache of all renewal, switch, resubscribe and " +"other order types for all subscriptions in your store. Expect slower " +"performance of checkout, renewal and other subscription related functions " +"after taking this action. The caches will be regenerated overtime as related " +"order queries are run." +msgstr "" +"Cela effacera le cache persistant des commandes de renouvellement, de " +"changement, de réabonnement etc. pour tous les abonnements dans votre " +"boutique. Attendez-vous à une performance plus lente de la validation de " +"commande, du renouvellement et des autres fonctions liées à l’abonnement " +"après avoir effectué cette action. Les caches sont régénérés au fur et à " +"mesure que les requêtes de commande liées sont exécutées." + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "Delete Related Order Cache" +msgstr "Supprimer le cache de commandes liées" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "" +"This will generate the persistent cache of all renewal, switch, resubscribe " +"and other order types for all subscriptions in your store. The caches will " +"be generated overtime in the background (via Action Scheduler)." +msgstr "" +"Cela générera le cache persistant des commandes de renouvellement, de " +"changement, de réabonnement etc. pour tous les abonnements dans votre " +"boutique. Les caches sont générés au fur et à mesure en arrière-plan (via le " +"Planificateur d’actions)." + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "Generate Related Order Cache" +msgstr "Générer le cache de commandes liées" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:55 +msgid "" +"This will clear the persistent cache of all of subscriptions stored against " +"users in your store. Expect slower performance of checkout, renewal and " +"other subscription related functions after taking this action. The caches " +"will be regenerated overtime as queries to find a given user's subscriptions " +"are run." +msgstr "" +"Cela effacera le cache persistant de tous les abonnements stockés avec les " +"utilisateurs dans votre boutique. Attendez-vous à une performance plus lente " +"de la validation de commande, du renouvellement et des autres fonctions " +"liées à l’abonnement après avoir effectué cette action. Les caches sont " +"régénérés au fur et à mesure que les requêtes pour trouver les abonnements " +"d’un utilisateur donné sont exécutées." + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:55 +msgid "Delete Customer Subscription Cache" +msgstr "Supprimer le cache d’abonnement client" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:54 +msgid "" +"This will generate the persistent cache for linking users with subscriptions." +" The caches will be generated overtime in the background (via Action " +"Scheduler)." +msgstr "" +"Cela générera le cache persistant pour lier les utilisateurs avec des " +"abonnements. Les caches sont générés au fur et à mesure en arrière-plan (via " +"le Planificateur d’actions)." + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:54 +msgid "Generate Customer Subscription Cache" +msgstr "Générer le cache d’abonnement client" + +#: includes/class-wcs-staging.php:55 +msgid "staging" +msgstr "préproduction" + +#. translators: 1-2: opening/closing tags - linked to staging site, 3: link +#. to live site. +#: includes/class-wcs-staging.php:40 +msgid "" +"Payment processing skipped - renewal order created on %1$sstaging site%2$s " +"under staging site lock. Live site is at %3$s" +msgstr "" +"Traitement du paiement ignoré - commande de renouvellement créée sur le " +"%1$ssite de préproduction%2$s sous verrouillage du site de préproduction. Le " +"site en direct se trouve sur %3$s" + +#: includes/class-wcs-retry-manager.php:344 +msgid "" +"Payment retry attempted on renewal order with multiple related subscriptions " +"with no payment method in common." +msgstr "" +"Nouvelle tentative de paiement sur une commande de renouvellement avec " +"plusieurs abonnements liés sans moyen de paiement en commun." + +#: includes/class-wcs-query.php:306 +msgid "" +"Endpoint for the My Account → Change Subscription Payment Method page" +msgstr "" +"Point de terminaison pour la page Mon compte → Modifier le moyen de " +"paiement d’abonnement" + +#: includes/class-wcs-query.php:305 +msgid "Subscription payment method" +msgstr "Moyen de paiement d’abonnement" + +#. translators: placeholder is a page number. +#: includes/class-wcs-query.php:106 +msgid "Subscriptions (page %d)" +msgstr "Abonnements (page %d)" + +#. translators: %s: invalid type of update argument. +#: includes/class-wcs-post-meta-cache-manager.php:199 +msgid "" +"Invalid update type: %s. Post update types supported are \"add\" or " +"\"delete\". Updates are done on post meta directly." +msgstr "" +"Type de mise à jour non valide : %s. Les types de mise à jour d’article sont " +"« ajouter » ou « supprimer ». Les mises à jour sont effectuées sur les " +"métadonnées d’article directement." + +#. translators: 1$-2$: opening and closing tags. +#: includes/class-wcs-permalink-manager.php:91 +msgid "" +"Error saving Subscriptions endpoints: %1$sSubscriptions%2$s, %1$sView " +"subscription%2$s and %1$sSubscription payment method%2$s cannot be the same. " +"The changes have been reverted." +msgstr "" +"Erreur lors de l’enregistrement des points de terminaisons des abonnements : " +"%1$sAbonnements%2$s, %1$sAfficher l’abonnement%2$s et %1$sMoyen de paiement " +"d’abonnement%2$s ne peuvent pas être identiques. Les modifications ont été " +"annulées." + +#. translators: 1: token display name, 2: opening link tag, 4: closing link +#. tag, 3: opening link tag. +#: includes/class-wcs-my-account-payment-methods.php:158 +msgid "" +"Would you like to update your subscriptions to use this new payment method - " +"%1$s?%2$sYes%4$s | %3$sNo%4$s" +msgstr "" +"Voulez-vous mettre à jour vos abonnements pour utiliser ce nouveau moyen de " +"paiement - %1$s ?%2$sOui%4$s | %3$sNon%4$s" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:155 +msgid "" +"Allow customers to turn on and off automatic renewals from their View " +"Subscription page." +msgstr "" +"Autorisez les clients à activer et désactiver les renouvellements " +"automatiques sur leur page Afficher l’abonnement." + +#: includes/class-wcs-my-account-auto-renew-toggle.php:154 +msgid "Display the auto renewal toggle" +msgstr "Afficher la bascule de renouvellement automatique" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:153 +msgid "Auto Renewal Toggle" +msgstr "Bascule de renouvellement automatique" + +#: includes/class-wcs-failed-scheduled-action-manager.php:163 +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:106 +msgid "Learn more" +msgstr "En savoir plus" + +#: includes/class-wcs-failed-scheduled-action-manager.php:158 +msgid "Ignore this error" +msgstr "Ignorer cette erreur" + +#: includes/class-wcs-cart-renewal.php:210 +msgid "" +"This order can no longer be paid because the corresponding subscription does " +"not require payment at this time." +msgstr "" +"Cette commande ne peut plus être payée car l’abonnement correspondant ne " +"nécessite pas de paiement pour le moment." + +#: includes/class-wcs-cached-data-manager.php:127 +msgid "new related order methods in WCS_Related_Order_Store" +msgstr "nouvelles méthodes de commande liée dans WCS_Related_Order_Store" + +#: includes/class-wcs-cached-data-manager.php:110 +#: includes/class-wcs-cached-data-manager.php:240 +msgid "Customer subscription caching is now handled by %1$s and %2$s." +msgstr "" +"La mise en cache d’abonnement client est maintenant gérée par %1$s et %2$s." + +#: includes/class-wcs-cached-data-manager.php:86 +msgid "Customer subscription caching is now handled by %1$s." +msgstr "La mise en cache d’abonnement client est maintenant gérée par %1$s." + +#: includes/class-wcs-cached-data-manager.php:79 +msgid "Related order caching is now handled by %1$s." +msgstr "La mise en cache de commande liée est maintenant gérée par %1$s." + +#: includes/class-wc-subscriptions-synchroniser.php:247 +msgid "" +"Subscriptions created within this many days prior to the Renewal Day will " +"not be charged at sign-up. Set to zero for all new Subscriptions to be " +"charged the full recurring amount. Must be a positive number." +msgstr "" +"Les abonnements créés avant la date de renouvellement ne seront pas facturés " +"lors de l’inscription. Définissez sur zéro pour que tous les nouveaux " +"abonnements soient facturés du montant récurrent complet. Doit être un " +"nombre positif." + +#: includes/class-wc-subscriptions-synchroniser.php:242 +msgid "Sign-up grace period" +msgstr "Période de grâce d’inscription" + +#: includes/class-wc-subscriptions-synchroniser.php:226 +msgid "Prorate First Renewal" +msgstr "Premier renouvellement au prorata" + +#. translators: placeholder is a switch type. +#: includes/class-wcs-switch-cart-item.php:309 +msgid "" +"Invalid switch type \"%s\". Switch must be one of: \"upgrade\", " +"\"downgrade\" or \"crossgrade\"." +msgstr "" +"Type de changement non valide « %s ». Le changement doit être : « mise à " +"niveau », « rétrogradation » ou « reclassement »." + +#: includes/class-wc-subscriptions-product.php:969 +msgid "" +"This variation can not be removed because it is associated with active " +"subscriptions. To remove this variation, please cancel and delete the " +"subscriptions for it." +msgstr "" +"Cette variante ne peut pas être supprimée car elle est associée à des " +"abonnements actifs. Pour supprimer cette variante, veuillez annuler et " +"supprimer les abonnements correspondants." + +#. translators: %1$s refers to the price. This string is meant to prefix +#. another string below, e.g. "$5 now, and $5 on March 15th each year" +#: includes/class-wc-subscriptions-product.php:291 +msgid "%1$s now, and " +msgstr "%1$s maintenant, et" + +#: includes/class-wc-subscriptions-coupon.php:1086 +msgid "Active for unlimited payments" +msgstr "Actif pour les paiements illimités" + +#. translators: %d refers to the number of payments the coupon can be used for. +#: includes/class-wc-subscriptions-coupon.php:1082 +msgid "Active for %d payment" +msgid_plural "Active for %d payments" +msgstr[0] "Actif pour %d paiement" +msgstr[1] "Actif pour %d paiements" + +#: includes/class-wc-subscriptions-coupon.php:950 +msgid "" +"Coupon will be limited to the given number of payments. It will then be " +"automatically removed from the subscription. \"Payments\" also includes the " +"initial subscription payment." +msgstr "" +"Le code de promotion sera limité au nombre donné de paiements. Il sera " +"ensuite automatiquement supprimé de l’abonnement. « Paiements » inclut " +"également le paiement d’abonnement initial." + +#: includes/class-wc-subscriptions-coupon.php:949 +msgid "Unlimited payments" +msgstr "Paiements illimités" + +#: includes/class-wc-subscriptions-coupon.php:948 +msgid "Active for x payments" +msgstr "Actif pour x paiements" + +#: includes/class-wc-subscriptions-coupon.php:933 +msgid "" +"Sorry, it seems there are no available payment methods which support the " +"recurring coupon you are using. Please contact us if you require assistance " +"or wish to make alternate arrangements." +msgstr "" +"Désolé, il semble qu’aucun moyen de paiement ne soit disponible pour le code " +"de promotion récurrent que vous utilisez. Veuillez nous contacter si vous " +"avez besoin d’aide ou si vous désirez mettre en place une alternative." + +#: includes/class-wc-subscriptions-coupon.php:717 +msgid "Discount" +msgstr "Remise" + +#: includes/class-wc-subscriptions-coupon.php:697 +msgid "Initial payment discount" +msgstr "Remise sur le paiement initial" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:797 +msgid "" +"Please log in to your account below to choose a new payment method for your " +"subscription." +msgstr "" +"Veuillez vous connecter à votre compte ci-dessous pour choisir un nouveau " +"moyen de paiement pour votre abonnement." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:380 +#: includes/class-wc-subscriptions-change-payment-gateway.php:382 +msgid "Payment method updated for all your current subscriptions." +msgstr "Moyen de paiement mis à jour pour tous vos abonnements actuels." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:340 +msgid "Payment method added." +msgstr "Moyen de paiement ajouté." + +#: includes/class-wc-subscription.php:1900 +msgid "" +"The \"all\" value for $order_type parameter is deprecated. It was a misnomer," +" as it did not return resubscribe orders. It was also inconsistent with " +"order type values accepted by wcs_get_subscription_orders(). Use array( " +"\"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or " +"\"any\" to receive all order types, including switch and resubscribe." +msgstr "" +"La valeur « tous » du paramètre $order_type est obsolète. Elle était " +"inappropriée, car elle ne renvoyait pas les commandes de réabonnement. Elle " +"était également incohérente avec les valeurs de type de commande acceptées " +"par wcs_get_subscription_orders(). Utilisez un tableau (« parent », " +"« renouvellement », « changement ») pour conserver le comportement précédent " +"ou « n’importe lequel » pour recevoir tous les types de commande, notamment " +"changement et réabonnement." + +#: includes/class-wc-subscription.php:1757 +msgid "Payment status marked complete." +msgstr "État de paiement marqué comme terminé." + +#: includes/class-wc-subscription.php:1326 +msgid "The creation date of a subscription can not be deleted, only updated." +msgstr "" +"La date de création d’un abonnement ne peut pas être supprimée, uniquement " +"mise à jour." + +#: includes/class-wc-subscription.php:604 +msgid "Error during subscription status transition." +msgstr "Une erreur est survenue pendant le changement d’état de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:564 +msgid "The date the subscription's latest order was paid, in GMT." +msgstr "" +"Date à laquelle la dernière commande de l’abonnement a été payée, au format " +"GMT." + +#: includes/api/class-wc-rest-subscriptions-controller.php:558 +msgid "The date the subscription's latest order was completed, in GMT." +msgstr "" +"Date à laquelle la dernière commande de l’abonnement a été terminée, au " +"format GMT." + +#: includes/api/class-wc-rest-subscriptions-controller.php:552 +msgid "The subscription's resubscribed subscription ID." +msgstr "ID d’abonnement réabonné de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:546 +msgid "" +"The subscription's original subscription ID if this is a resubscribed " +"subscription." +msgstr "" +"ID d’abonnement original de l’abonnement s’il s’agit d’abonnement réabonné." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:855 +msgid "New Subscriptions" +msgstr "Nouveaux abonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:535 +msgid "" +"The number of subscriptions created during this period, either by being " +"manually created, imported or a customer placing an order. This includes " +"orders pending payment." +msgstr "" +"Nombre d’abonnements créés pendant cette période, soit créés manuellement, " +"soit importés, soit via la commande d’un client. Cela inclut les commandes " +"en attente de paiement." + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:20 +msgid "Product" +msgstr "Produit" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:50 +msgid "The average value of all customers' sign-up, switch and renewal orders." +msgstr "" +"Valeur moyenne de toutes les commandes d’inscription, de changement et de " +"renouvellement des clients." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:47 +msgid "" +"The total number of sign-up, switch and renewal orders placed with your " +"store with a paid status (i.e. processing or complete)." +msgstr "" +"Nombre total des commandes d’inscription, de changement et de renouvellement " +"placées avec votre boutique avec un état payé (c.-à-d. traitement ou terminé)" +"." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:46 +msgid "" +"The total number of subscriptions with a status other than pending or " +"trashed." +msgstr "" +"Nombre total d’abonnements avec un état autre que en attente ou déplacé vers " +"la corbeille." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:45 +msgid "" +"The total number of subscriptions with a status of active or pending " +"cancellation." +msgstr "" +"Nombre total d’abonnements avec un état d’annulation active ou en attente." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:44 +msgid "" +"The number of unique customers with a subscription of any status other than " +"pending or trashed." +msgstr "" +"Nombre de clients uniques avec un abonnement avec un état autre que en " +"attente ou déplacé vers la corbeille." + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, +#. respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:248 +msgid "%2$s%1$s cancellation%3$s subscription cancellations this month" +msgid_plural "%2$s%1$s cancellations%3$s subscription cancellations this month" +msgstr[0] "%2$s%1$s annulation%3$s annulations d’abonnement ce mois-ci" +msgstr[1] "%2$s%1$s annulations%3$s annulations d’abonnement ce mois-ci" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-dashboard.php:240 +msgid "%s renewal revenue this month" +msgstr "%s revenu de renouvellement ce mois-ci" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, +#. respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:232 +msgid "%2$s%1$s renewal%3$s subscription renewals this month" +msgid_plural "%2$s%1$s renewals%3$s subscription renewals this month" +msgstr[0] "%2$s%1$s renouvellement%3$s renouvellements d’abonnement ce mois-ci" +msgstr[1] "" +"%2$s%1$s renouvellements%3$s renouvellements d’abonnement ce mois-ci" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-dashboard.php:224 +msgid "%s signup revenue this month" +msgstr "%s revenu d’inscription ce mois-ci" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, +#. respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:216 +msgid "%2$s%1$s signup%3$s subscription signups this month" +msgid_plural "%2$s%1$s signups%3$s subscription signups this month" +msgstr[0] "%2$s%1$s inscription%3$s inscriptions d’abonnement ce mois-ci" +msgstr[1] "%2$s%1$s inscriptions%3$s inscriptions d’abonnement ce mois-ci" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:23 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:72 +msgid "Payment:" +msgstr "Paiement" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:214 +msgid "Customer add payment method page →" +msgstr "Page d’ajout de moyen de paiement du client →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:212 +msgid "Customer change payment method page →" +msgstr "Page de changement de moyen de paiement du client →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:127 +msgid "Select an order…" +msgstr "Sélectionner une commande…" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:121 +msgid "Parent order:" +msgstr "Commande parente :" + +#. translators: placeholder is an order number. +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:114 +msgid "#%1$s" +msgstr "n°%1$s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:110 +msgid "Parent order: " +msgstr "Commande parente : " + +#: includes/admin/class-wcs-admin-system-status.php:72 +msgid "This section shows information about payment gateway feature support." +msgstr "" +"Cette section contient des informations sur la prise en charge de la " +"fonctionnalité de passerelle de paiement." + +#: includes/admin/class-wcs-admin-system-status.php:71 +msgid "Payment Gateway Support" +msgstr "Prise en charge de la passerelle de paiement" + +#: includes/admin/class-wcs-admin-system-status.php:67 +msgid "This section shows information about Subscription payment methods." +msgstr "" +"Cette section contient des informations sur les moyens de paiement " +"d’abonnement." + +#: includes/admin/class-wcs-admin-system-status.php:66 +msgid "Subscriptions by Payment Gateway" +msgstr "Abonnements par passerelle de paiement" + +#: includes/admin/class-wcs-admin-system-status.php:62 +msgid "This section shows general information about the store." +msgstr "Cette section contient des informations générales sur la boutique." + +#: includes/admin/class-wcs-admin-system-status.php:61 +msgid "Store Setup" +msgstr "Configuration de la boutique" + +#: includes/admin/class-wcs-admin-meta-boxes.php:253 +msgid "Create pending parent order requested by admin action." +msgstr "" +"Créez une commande parente en attente demandée par une action de " +"l’administrateur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:183 +msgid "Create pending parent order" +msgstr "Créer une commande parente en attente" + +#: includes/admin/class-wc-subscriptions-admin.php:2036 +msgid "Note that purchasing a subscription still requires an account." +msgstr "Notez que l’achat d’un abonnement nécessite toujours un compte." + +#: includes/admin/class-wc-subscriptions-admin.php:1595 +msgid "We can't find a paid subscription order for this user." +msgstr "" +"Nous ne trouvons pas de commande d’abonnement payée pour cet utilisateur." + +#: includes/admin/class-wc-subscriptions-admin.php:1344 +msgid "" +"Allow a subscription product with a $0 initial payment to be purchased " +"without providing a payment method. The customer will be required to provide " +"a payment method at the end of the initial period to keep the subscription " +"active." +msgstr "" +"Autorisez l’achat d’un produit d’abonnement avec un paiement initial de 0 $ " +"sans fournir de moyen de paiement. Le client devra fournir un moyen de " +"paiement à la fin de la période initiale pour maintenir l’abonnement actif." + +#: includes/admin/class-wc-subscriptions-admin.php:1340 +msgid "Allow $0 initial checkout without a payment method." +msgstr "" +"Autorisez une validation de commande initiale de 0 $ sans moyen de paiement." + +#: includes/admin/class-wc-subscriptions-admin.php:1339 +msgid "$0 Initial Checkout" +msgstr "Validation de commande initiale de 0 $" + +#: includes/admin/class-wc-subscriptions-admin.php:868 +msgid "" +"Because of this, it is not recommended as a payment method for Subscriptions " +"unless it is the only available option for your country." +msgstr "" +"Pour cette raison, il n’est pas recommandé comme moyen de paiement pour les " +"abonnements, sauf s’il s’agit de la seule option disponible pour votre pays." + +#: includes/admin/class-wc-subscriptions-admin.php:868 +msgid "" +"PayPal Standard has a number of limitations and does not support all " +"subscription features." +msgstr "" +"PayPal Standard présente un certain nombre de limites et ne prend pas en " +"charge toutes les fonctionnalités d’abonnement." + +#: includes/admin/class-wc-subscriptions-admin.php:2050 +msgid "" +"The product type can not be changed because this product is associated with " +"subscriptions." +msgstr "" +"Le type de produit ne peut pas être modifié car ce produit est associé à des " +"abonnements." + +#: includes/admin/class-wc-subscriptions-admin.php:836 +msgid "Delete all variations without a subscription" +msgstr "Supprimer toutes les variantes sans abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:447 +msgid "Subscription pricing" +msgstr "Tarifs d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:221 +msgid "Virtual" +msgstr "Virtuel" + +#: includes/admin/class-wc-subscriptions-admin.php:220 +msgid "Downloadable" +msgstr "Téléchargeable" + +#. translators: 1: relation type, 2: list of valid relation types. +#: includes/abstracts/abstract-wcs-related-order-store.php:148 +msgid "" +"Invalid relation type: %1$s. Order relationship type must be one of: %2$s." +msgstr "" +"Type de relation non valide : %1$s. Le type de relation de commande doit " +"être : %2$s." + +#: templates/emails/subscription-info.php:35 +msgctxt "subscription number in email table. (eg: #106)" +msgid "#%s" +msgstr "n°%s" + +#. translators: $1-$3: opening and closing tags $2: subscription's order +#. number +#: templates/emails/email-order-details.php:27 +msgctxt "Used in email notification" +msgid "Subscription %1$s#%2$s%3$s" +msgstr "Abonnement %1$sn°%2$s%3$s" + +#. translators: $1-$2: opening and closing tags $3: order's order number +#. $4: date of order in tags +#: includes/upgrades/templates/wcs-about.php:206 +msgid "" +"Subscriptions also now uses the renewal order to setup the cart for %smanual " +"renewals%s, making it easier to add products or discounts to a single " +"renewal paid manually." +msgstr "" +"Subscriptions utilise désormais la commande de renouvellement pour " +"configurer le panier pour les %srenouvellements manuels%s, ce qui facilite " +"l’ajout de produits ou de remises à un seul renouvellement payé manuellement." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:202 +msgid "" +"Subscriptions 2.1 now passes the renewal order's total, making it possible " +"to add a fee or discount to the renewal order with simple one-liners like " +"%s$order->add_fee()%s or %s$order->add_coupon()%s." +msgstr "" +"Subscriptions 2.1 transmet désormais le total de la commande de " +"renouvellement, ce qui permet d’ajouter des frais ou une remise à la " +"commande de renouvellement avec des mots simples comme %s$order->add_fee()%s " +"ou %s$order->add_coupon()%s." + +#: includes/upgrades/templates/wcs-about.php:199 +msgid "" +"In previous versions of Subscriptions, the subscription total was passed to " +"payment gateways as the amount to charge for automatic renewal payments. " +"This made it unnecessarily complicated to add one-time fees or discounts to " +"a renewal." +msgstr "" +"Dans les versions précédentes de Subscriptions, le total d’abonnement était " +"transmis aux passerelles de paiement comme montant à facturer pour les " +"paiements de renouvellement automatique. Cela compliquait inutilement " +"l’ajout de frais uniques ou de remises à un renouvellement." + +#. translators: placeholders are opening and closing code tags +#: includes/upgrades/templates/wcs-about.php:197 +msgid "Honour Renewal Order Data" +msgstr "Honorer les données de commande de renouvellement" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:187 +msgid "" +"Want the details of a specific subscription? Get %s/wp-" +"json/wc/v1/subscriptions//%s." +msgstr "" +"Vous voulez les détails d’un abonnement spécifique ? Obtenez %s/wp-" +"json/wc/v1/subscriptions//%s." + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:183 +msgid "" +"Want to list all the subscriptions on a site? Get %s/wp-" +"json/wc/v1/subscriptions%s." +msgstr "" +"Vous voulez répertorier tous les abonnements sur un site ? Obtenez %s/wp-" +"json/wc/v1/subscriptions%s." + +#: includes/upgrades/templates/wcs-about.php:180 +msgid "" +"Your applications can now create, read, update or delete subscriptions via " +"RESTful API endpoints with the same design as the latest version of " +"WooCommerce's REST API endpoints." +msgstr "" +"Vos applications peuvent désormais créer, lire, mettre à jour ou supprimer " +"des abonnements via des points de terminaison API RESTful avec la même " +"conception que la dernière version des points de terminaison API RESTful de " +"WooCommerce." + +#: includes/upgrades/templates/wcs-about.php:179 +msgid "" +"Subscriptions 2.1 adds support for subscription data to this infrastructure." +msgstr "" +"Subscriptions 2.1 ajoute la prise en charge des données d’abonnement à cette " +"infrastructure." + +#. translators: $1: opening tag linking to WC API docs, $2: closing +#. tag, $3: opening tag linking to WP API docs, $4: closing tag +#: includes/upgrades/templates/wcs-about.php:177 +msgid "" +"WooCommerce 2.6 added support for %1$sREST API%2$s endpoints built on " +"WordPress core's %3$sREST API%4$s infrastructure." +msgstr "" +"WooCommerce 2.6 a ajouté la prise en charge des points de terminaison " +"%1$sAPI REST%2$s créés sur l’infrastructure %3$sAPI REST%4$s du cÅ“ur de " +"WordPress." + +#: includes/upgrades/templates/wcs-about.php:174 +msgid "WP REST API Endpoints" +msgstr "Points de terminaison API REST WP" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:166 +msgid "" +"To apply a specific rule based on certain conditions, like high value orders " +"or an infrequent renewal schedule, you can use the retry specific " +"%s'wcs_get_retry_rule'%s filter. This provides the ID of the renewal order " +"for the failed payment, which can be used to find information about the " +"products, subscription and totals to which the failed payment relates." +msgstr "" +"Pour appliquer une règle spécifique basée sur certaines conditions, comme " +"des commandes de valeur élevée ou un calendrier de renouvellement peu " +"fréquent, vous pouvez utiliser le filtre %s'wcs_get_retry_rule'%s spécifique " +"aux nouvelles tentatives. Cela fournit l’ID de la commande de renouvellement " +"pour le paiement échoué, qui peut être utilisé pour trouver des informations " +"sur les produits, l’abonnement et les totaux auxquels le paiement échoué se " +"rapporte." + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:162 +msgid "" +"With the %s'wcs_default_retry_rules'%s filter, you can define a set of " +"default rules to apply to all failed payments in your store." +msgstr "" +"Avec le filtre %s'wcs_default_retry_rules'%s, vous pouvez définir un " +"ensemble de règles par défaut à appliquer à tous les paiements échoués dans " +"votre boutique." + +#: includes/upgrades/templates/wcs-about.php:159 +msgid "" +"The best part about the new automatic retry system is that the retry rules " +"are completely customisable." +msgstr "" +"La meilleure partie du nouveau système de nouvelle tentative automatique est " +"que les règles de nouvelle tentative sont entièrement personnalisables." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:157 +msgid "Customise Retry Rules" +msgstr "Personnaliser des règles de nouvelle tentative" + +#: includes/upgrades/templates/wcs-about.php:139 +msgid "" +"With WooCommerce Subscribe All the Things, they can! This experimental " +"extension is exploring how to convert any product, including Product Bundles " +"and Composite Products, into a subscription product. It also offers " +"customers a way to subscribe to a cart of non-subscription products." +msgstr "" +"Avec WooCommerce Subscribe All the Things, ils le peuvent ! Cette extension " +"expérimentale explore comment convertir n’importe quel produit, dont des " +"groupes de produits et des produits composites, en un produit d’abonnement. " +"Elle permet aux clients de s’abonner à un panier de produits sans abonnement." + +#: includes/upgrades/templates/wcs-about.php:138 +msgid "" +"Want your customers to be able to subscribe to non-subscription products?" +msgstr "" +"Vous voulez que vos clients puissent s’abonner à des produits sans " +"abonnement ?" + +#: includes/upgrades/templates/wcs-about.php:137 +msgid "Subscribe All the Things" +msgstr "Subscribe All the Things" + +#: includes/upgrades/templates/wcs-about.php:128 +msgid "" +"This free extension makes it possible to migrate subscribers from 3rd party " +"systems to WooCommerce. It also makes it possible to export your " +"subscription data for analysis in spreadsheet tools or 3rd party apps." +msgstr "" +"Cette extension gratuite permet de migrer des abonnés de systèmes tiers vers " +"WooCommerce. Elle permet également d’exporter vos données d’abonnement pour " +"analyse dans des outils de feuille de calcul ou des applications tierces." + +#: includes/upgrades/templates/wcs-about.php:127 +msgid "" +"Import subscriptions to WooCommerce via CSV, or export your subscriptions " +"from WooCommerce to a CSV with the WooCommerce Subscriptions " +"Importer/Exporter extension." +msgstr "" +"Importez des abonnements vers WooCommerce via CSV ou exportez vos " +"abonnements depuis WooCommerce vers un fichier CSV avec l’extension " +"WooCommerce Subscriptions Importer/Exporter." + +#: includes/upgrades/templates/wcs-about.php:117 +msgid "" +"The Gifting extension makes it possible for one person to purchase a " +"subscription product for someone else. It then shares control of the " +"subscription between the purchaser and recipient, allowing both to manage " +"the subscription over its lifecycle." +msgstr "" +"L’extension Gifting permet à une personne d’acheter un produit d’abonnement " +"pour quelqu’un d’autre. Elle partage ensuite le contrôle de l’abonnement " +"entre l’acheteur et le destinataire, ce qui permet aux deux de gérer " +"l’abonnement tout au long de son cycle de vie." + +#: includes/upgrades/templates/wcs-about.php:116 +msgid "" +"What happens when a customer wants to purchase a subscription product for " +"someone else?" +msgstr "" +"Que se passe-t-il quand un client veut acheter un produit d’abonnement pour " +"quelqu’un d’autre ?" + +#: includes/upgrades/templates/wcs-about.php:109 +msgid "" +"That's not all we've working on for the last 12 months when it comes to " +"Subscriptions. We've also released mini-extensions to help you get the most " +"from your subscription store." +msgstr "" +"Ce n’est pas tout ce sur quoi nous travaillons depuis 12 mois en ce qui " +"concerne Subscriptions. Nous avons également publié des mini-extensions pour " +"vous aider à tirer le meilleur parti de votre boutique d’abonnement." + +#: includes/upgrades/templates/wcs-about.php:108 +msgid "But wait, there's more!" +msgstr "Attendez, vous avez encore tant à découvrir !" + +#: includes/upgrades/templates/wcs-about.php:99 +msgid "View Email Settings" +msgstr "Voir les paramètres d’e-mail" + +#: includes/upgrades/templates/wcs-about.php:97 +msgid "" +"These emails can be enabled, disabled and customised under the %sWooCommerce " +"> Settings > Emails%s administration screen." +msgstr "" +"Ces e-mails peuvent être activés, désactivés et personnalisés sur l’écran " +"d’administration %sWooCommerce > Réglages > E-mails%s." + +#: includes/upgrades/templates/wcs-about.php:95 +msgid "a subscription expires" +msgstr "un abonnement expire" + +#: includes/upgrades/templates/wcs-about.php:94 +msgid "an automatic payment fails" +msgstr "un paiement automatique échoue" + +#: includes/upgrades/templates/wcs-about.php:93 +msgid "a customer suspends a subscription" +msgstr "un client suspend un abonnement" + +#: includes/upgrades/templates/wcs-about.php:91 +msgid "" +"Subscriptions 2.1 also introduces a number of new emails to notify you when:" +msgstr "" +"Subscriptions 2.1 introduit également un certain nombre de nouveaux e-mails " +"pour vous informer quand :" + +#: includes/upgrades/templates/wcs-about.php:90 +msgid "New Subscription Emails" +msgstr "Nouveaux e-mails d’abonnement" + +#: includes/upgrades/templates/wcs-about.php:78 +msgid "Enable Automatic Retry" +msgstr "Activer la nouvelle tentative automatique" + +#: includes/upgrades/templates/wcs-about.php:76 +msgid "" +"The retry system is disabled by default. To enable it, visit the " +"Subscriptions settings administration screen." +msgstr "" +"Le système de nouvelle tentative est désactivé par défaut. Pour l’activer, " +"visitez l’écran d’administration de réglages des abonnements." + +#: includes/upgrades/templates/wcs-about.php:74 +msgid "the status applied to the renewal order and subscription" +msgstr "l’état appliqué à la commande de renouvellement et à l’abonnement" + +#: includes/upgrades/templates/wcs-about.php:73 +msgid "emails sent to the customer and store manager" +msgstr "les e-mails envoyés au client et au gérant de la boutique" + +#: includes/upgrades/templates/wcs-about.php:72 +msgid "how long to wait between retry attempts" +msgstr "la durée d’attente entre les nouvelles tentatives" + +#: includes/upgrades/templates/wcs-about.php:71 +msgid "the total number of retry attempts" +msgstr "le nombre total de nouvelles tentatives" + +#: includes/upgrades/templates/wcs-about.php:69 +msgid "" +"By default, Subscriptions will retry the payment 5 times over 7 days. The " +"rules that control the retry system can be modified to customise:" +msgstr "" +"Par défaut, Subscriptions tentera le paiement 5 fois pendant 7 jours. Les " +"règles qui contrôlent le système de nouvelle tentative peuvent être " +"modifiées pour personnaliser :" + +#: includes/upgrades/templates/wcs-about.php:68 +msgid "" +"Failed recurring payments can now be retried automatically. This helps " +"recover revenue that would otherwise be lost due to payment methods being " +"declined only temporarily." +msgstr "" +"Les paiements récurrents échoués peuvent maintenant être retentés " +"automatiquement. Cela permet de récupérer les revenus qui seraient autrement " +"perdus en raison du refus temporaire des moyens de paiement." + +#: includes/upgrades/templates/wcs-about.php:67 +msgid "Automatic Failed Payment Retry" +msgstr "Nouvelle tentative automatique de paiement échouée" + +#: includes/upgrades/templates/wcs-about.php:54 +msgid "View Reports" +msgstr "Voir les rapports" + +#: includes/upgrades/templates/wcs-about.php:52 +msgid "" +"Prior to Subscriptions 2.1, they were not easy to answer. Subscriptions 2.1 " +"introduces new reports to answer these questions, and many more." +msgstr "" +"Avant Subscriptions 2.1, il n’était pas facile d’y répondre. Subscriptions 2." +"1 introduit de nouveaux rapports pour répondre à ces questions, et bien " +"d’autres." + +#: includes/upgrades/templates/wcs-about.php:51 +msgid "These are important questions for any subscription commerce business." +msgstr "" +"Ce sont des questions importantes pour toute entreprise de commerce par " +"abonnement." + +#: includes/upgrades/templates/wcs-about.php:50 +msgid "" +"How many customers stay subscribed for more than 6 months? What is the " +"average lifetime value of your subscribers? How much renewal revenue will " +"your store earn next month?" +msgstr "" +"Combien de clients restent abonnés pendant plus de 6 mois ? Quelle est la " +"valeur moyenne de la durée de vie de vos abonnés ? Combien de revenus de " +"renouvellement votre boutique gagnera-t-elle le mois prochain ?" + +#: includes/upgrades/templates/wcs-about.php:49 +msgid "Subscription Reports" +msgstr "Rapports d’abonnement" + +#: includes/upgrades/templates/wcs-about.php:23 +msgid "" +"Version 2.1 introduces some great new features requested by store managers " +"just like you (and possibly even by %syou%s)." +msgstr "" +"La version 2.1 introduit de nouvelles fonctionnalités géniales demandées par " +"des gérants de boutique comme vous (et peut-être même par %svous%s)." + +#: includes/upgrades/templates/wcs-about.php:19 +msgid "Welcome to Subscriptions 2.1!" +msgstr "Bienvenue dans Subscriptions 2.1 !" + +#: includes/upgrades/class-wcs-upgrade-2-2-7.php:60 +msgid "Subscription end date in the past" +msgstr "Date de fin d’abonnement dans le passé" + +#: includes/payment-retry/class-wcs-retry-post-store.php:46 +msgid "No retries found" +msgstr "Aucune nouvelle tentative trouvée" + +#: includes/payment-retry/class-wcs-retry-post-store.php:45 +msgid "Search Renewal Payment Retries" +msgstr "Rechercher de nouvelles tentatives de paiement de renouvellement" + +#: includes/payment-retry/class-wcs-retry-post-store.php:43 +#: includes/payment-retry/class-wcs-retry-post-store.php:44 +msgid "View Retry" +msgstr "Voir la nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:42 +msgid "New Retry" +msgstr "Nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:41 +msgid "Edit Retry" +msgstr "Modifier la nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:39 +msgid "Add New Retry" +msgstr "Ajouter une nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:36 +msgid "Renewal Payment Retry" +msgstr "Nouvelle tentative de paiement de renouvellement" + +#: includes/payment-retry/class-wcs-retry-post-store.php:25 +msgid "" +"Payment retry posts store details about the automatic retry of failed " +"renewal payments." +msgstr "" +"La nouvelle tentative de paiement sauvegarde les détails sur la nouvelle " +"tentative automatique des paiements de renouvellement échoués." + +#. translators: 1,2: opening/closing link tags (to documentation). +#: includes/payment-retry/class-wcs-retry-admin.php:150 +msgid "" +"Attempt to recover recurring revenue that would otherwise be lost due to " +"payment methods being declined only temporarily. %1$sLearn more%2$s." +msgstr "" +"Tentative de récupération des revenus récurrents qui seraient autrement " +"perdus en raison du refus temporaire des moyens de paiement. %1$sEn savoir " +"plus%2$s." + +#: includes/payment-retry/class-wcs-retry-admin.php:145 +msgid "Enable automatic retry of failed recurring payments" +msgstr "" +"Activer la nouvelle tentative automatique des paiements de renouvellement " +"échoués" + +#: includes/payment-retry/class-wcs-retry-admin.php:144 +msgid "Retry Failed Payments" +msgstr "Retenter les paiements échoués" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:116 +msgid "%d Cancelled Payment Retry" +msgid_plural "%d Cancelled Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement annulée" +msgstr[1] "%d Nouvelles tentatives de paiement annulées" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:112 +msgid "%d Successful Payment Retry" +msgid_plural "%d Successful Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement réussie" +msgstr[1] "%d Nouvelles tentatives de paiement réussies" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:108 +msgid "%d Failed Payment Retry" +msgid_plural "%d Failed Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement échouée" +msgstr[1] "%d Nouvelles tentatives de paiement échouées" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:104 +msgid "%d Processing Payment Retry" +msgid_plural "%d Processing Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement en cours de traitement" +msgstr[1] "%d Nouvelles tentatives de paiement en cours de traitement" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:100 +msgid "%d Pending Payment Retry" +msgid_plural "%d Pending Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement en attente" +msgstr[1] "%d Nouvelles tentatives de paiement en attente" + +#: includes/payment-retry/class-wcs-retry-admin.php:46 +msgid "Automatic Failed Payment Retries" +msgstr "Nouvelles tentatives automatiques de paiement échoué" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:113 +msgid "PayPal API error - credentials are incorrect." +msgstr "Erreur d’API PayPal - les identifiants de connexion sont incorrects." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:641 +msgid "Invalid PayPal IPN Payload: unable to find matching subscription." +msgstr "" +"Charge utile PayPal IPN non valide : abonnement correspondant introuvable." + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:286 +msgid "PayPal Subscription ID:" +msgstr "ID d’abonnement PayPal :" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:194 +msgid "Ignore this error (not recommended)" +msgstr "Ignorer cette erreur (non recommandé)" + +#: includes/emails/class-wcs-email-payment-retry.php:30 +msgid "" +"[{site_title}] Automatic payment failed for {order_number}, retry scheduled " +"to run {retry_time}" +msgstr "" +"[{site_title}] Paiement automatique échoué pour {order_number}, nouvelle " +"tentative planifiée le {retry_time}" + +#: includes/emails/class-wcs-email-payment-retry.php:29 +msgid "Automatic renewal payment failed" +msgstr "Paiement de renouvellement automatique échoué" + +#: includes/emails/class-wcs-email-payment-retry.php:27 +msgid "" +"Payment retry emails are sent to chosen recipient(s) when an attempt to " +"automatically process a subscription renewal payment has failed and a retry " +"rule has been applied to retry the payment in the future." +msgstr "" +"Les e-mails de nouvelle tentative de paiement sont envoyés au(x) " +"destinataire(s) choisi(s) lorsqu’une tentative de traitement automatique " +"d’un paiement de renouvellement d’abonnement a échoué et qu’une règle de " +"nouvelle tentative a été appliquée pour retenter le paiement à l’avenir." + +#: includes/emails/class-wcs-email-payment-retry.php:26 +msgid "Payment Retry" +msgstr "Nouvelle tentative de paiement" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:29 +msgid "Subscription Suspended" +msgstr "Abonnement suspendu" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:27 +msgid "" +"Suspended Subscription emails are sent when a customer manually suspends " +"their subscription." +msgstr "" +"Des e-mails Abonnement suspendu sont envoyés lorsqu’un client suspend " +"manuellement son abonnement." + +#: includes/emails/class-wcs-email-on-hold-subscription.php:26 +msgid "Suspended Subscription" +msgstr "Abonnement suspendu" + +#: includes/emails/class-wcs-email-expired-subscription.php:78 +#: includes/emails/class-wcs-email-on-hold-subscription.php:78 +msgid "Subscription argument passed in is not an object." +msgstr "L’argument d’abonnement transmis n’est pas un objet." + +#: includes/emails/class-wcs-email-expired-subscription.php:29 +msgid "Subscription Expired" +msgstr "Abonnement expiré" + +#: includes/emails/class-wcs-email-expired-subscription.php:27 +msgid "" +"Expired Subscription emails are sent when a customer's subscription expires." +msgstr "" +"Des e-mails Abonnement expiré sont envoyés lorsque l’abonnement d’un client " +"expire." + +#: includes/emails/class-wcs-email-expired-subscription.php:26 +msgid "Expired Subscription" +msgstr "Abonnement expiré" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:41 +msgid "" +"Sent to a customer when the subscription is due for renewal and the renewal " +"requires a manual payment, either because it uses manual renewals or the " +"automatic recurring payment failed for the initial attempt and all automatic " +"retries (if any). The email contains renewal order information and payment " +"links." +msgstr "" +"Envoyé à un client lorsque l’abonnement doit être renouvelé et que le " +"renouvellement nécessite un paiement manuel, soit parce qu’il utilise des " +"renouvellements manuels, soit parce que le paiement récurrent automatique a " +"échoué à la première tentative et toutes les nouvelles tentatives " +"automatiques (le cas échéant). L’e-mail contient des informations sur la " +"commande de renouvellement et des liens de paiement." + +#: includes/emails/class-wcs-email-customer-payment-retry.php:33 +msgid "Automatic payment failed for order {order_number}" +msgstr "Paiement automatique échoué pour la commande {order_number}" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:32 +msgid "Automatic payment failed for {order_number}, we will retry {retry_time}" +msgstr "" +"Paiement automatique échoué pour {order_number}, nous retenterons le " +"{retry_time}" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:25 +msgid "" +"Sent to a customer when an attempt to automatically process a subscription " +"renewal payment has failed and a retry rule has been applied to retry the " +"payment in the future. The email contains the renewal order information, " +"date of the scheduled retry and payment links to allow the customer to pay " +"for the renewal order manually instead of waiting for the automatic retry." +msgstr "" +"Envoyé à un client lorsqu’une tentative de traitement automatique d’un " +"paiement de renouvellement d’abonnement a échoué et qu’une règle de nouvelle " +"tentative a été appliquée pour retenter le paiement à l’avenir. L’e-mail " +"contient des informations sur la commande de renouvellement, la date de la " +"nouvelle tentative planifiée et des liens de paiement pour permettre au " +"client de payer la commande de renouvellement manuellement au lieu " +"d’attendre la nouvelle tentative automatique." + +#: includes/emails/class-wcs-email-customer-payment-retry.php:24 +msgid "Customer Payment Retry" +msgstr "Nouvelle tentative de paiement du client" + +#: includes/class-wcs-webhooks.php:113 +msgid " Subscription switched" +msgstr "Abonnement changé" + +#: includes/class-wcs-query.php:297 +msgid "Endpoint for the My Account → View Subscription page" +msgstr "" +"Point de terminaison pour la page Mon compte → Afficher l’abonnement" + +#: includes/class-wcs-query.php:288 +msgid "Endpoint for the My Account → Subscriptions page" +msgstr "Point de terminaison pour la page Mon compte → Abonnements" + +#: includes/class-wcs-query.php:131 +msgid "My Subscription" +msgstr "Mon abonnement" + +#. translators: $1: the token/credit card label, 2$-3$: opening and closing +#. strong and link tags +#: includes/class-wcs-my-account-payment-methods.php:103 +msgid "" +"The deleted payment method was used for automatic subscription payments. To " +"avoid failed renewal payments in future the subscriptions using this payment " +"method have been updated to use your %1$s. To change the payment method of " +"individual subscriptions go to your %2$sMy Account > Subscriptions%3$s page." +msgstr "" +"Le moyen de paiement supprimé était utilisé pour les paiements d’abonnement " +"automatiques. Pour éviter l’échec des paiements de renouvellement à l’avenir," +" les abonnements utilisant ce moyen de paiement ont été mis à jour pour " +"utiliser votre %1$s. Pour modifier le moyen de paiement d’abonnements " +"individuels, allez sur la page %2$sMon compte > Abonnements%3$s." + +#: includes/class-wcs-my-account-payment-methods.php:80 +msgid "" +"The deleted payment method was used for automatic subscription payments, we " +"couldn't find an alternative token payment method token to change your " +"subscriptions to." +msgstr "" +"Le moyen de paiement supprimé était utilisé pour les paiements d’abonnement " +"automatiques. Nous n’avons pas pu trouver un autre jeton de moyen de " +"paiement pour modifier vos abonnements." + +#. translators: %s: order number. +#: includes/class-wcs-cart-resubscribe.php:320 +msgid "Customer resubscribed in order #%s" +msgstr "Client réabonné dans la commande n°%s" + +#: includes/class-wcs-cart-renewal.php:227 +msgid "Complete checkout to renew your subscription." +msgstr "Terminez la validation de commande pour renouveler votre abonnement." + +#: includes/class-wcs-cached-data-manager.php:225 +msgid "Weekly" +msgstr "Hebdomadaire" + +#: includes/class-wc-subscriptions-synchroniser.php:311 +msgid "Month for Synchronisation" +msgstr "Mois de synchronisation" + +#: includes/class-wc-subscriptions-synchroniser.php:48 +msgid "Synchronise renewals" +msgstr "Synchroniser les renouvellements" + +#: includes/class-wc-subscriptions-switcher.php:1974 +msgid "The item on the switch order cannot be found." +msgstr "L’article sur la commande de changement est introuvable." + +#: includes/class-wc-subscriptions-switcher.php:1972 +msgid "The original subscription item being switched cannot be found." +msgstr "" +"L’article d’abonnement original en cours de changement est introuvable." + +#: includes/class-wc-subscriptions-switcher.php:1377 +msgid "You can only switch to a subscription product." +msgstr "Vous pouvez passer uniquement à un produit d’abonnement." + +#. translators: %s: order number. +#: includes/class-wc-subscriptions-switcher.php:1126 +msgid "Switch order cancelled due to a new switch order being created #%s." +msgstr "" +"Commande de changement annulée en raison d’une nouvelle commande de " +"changement créée n° %s." + +#: includes/class-wc-subscriptions-order.php:745 +msgid "All orders types" +msgstr "Tous les types de commande" + +#: includes/class-wc-subscriptions-order.php:473 +msgid "Parent Order" +msgstr "Commande parente" + +#: includes/class-wc-subscriptions-order.php:471 +msgid "Resubscribe Order" +msgstr "Commande de réabonnement" + +#: includes/class-wc-subscriptions-order.php:469 +msgid "Renewal Order" +msgstr "Commande de renouvellement" + +#: includes/class-wc-subscriptions-order.php:449 +msgid "Subscription Relationship" +msgstr "Relation d’abonnement" + +#. translators: placeholder is a subscription ID. +#. translators: %d: subscription ID. +#: includes/class-wc-subscriptions-manager.php:167 +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:215 +msgid "Subscription doesn't exist in scheduled action: %d" +msgstr "L’abonnement n’existe pas dans l’action planifiée : %d" + +#. translators: placeholder is an order note. +#: includes/class-wc-subscriptions-manager.php:124 +msgid "Error: Unable to create renewal order with note \"%s\"" +msgstr "" +"Erreur : impossible de créer une commande de renouvellement avec la note " +"« %s »" + +#: includes/class-wc-subscriptions-coupon.php:714 +msgid "Renewal Discount" +msgstr "Remise sur le renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:696 +msgid "Renewal cart discount" +msgstr "Remise sur le panier de renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:695 +msgid "Renewal product discount" +msgstr "Remise sur le produit de renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:694 +msgid "Renewal % discount" +msgstr "Remise % sur le renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:512 +msgid "Sorry, only recurring coupons can be applied to subscriptions." +msgstr "" +"Désolé, seuls les codes promo récurrents peuvent être appliqués aux " +"abonnements." + +#. translators: placeholder is coupon code +#: includes/class-wc-subscriptions-coupon.php:509 +msgid "" +"Sorry, \"%s\" can only be applied to subscription parent orders which " +"contain a product with signup fees." +msgstr "" +"Désolé, « %s » ne peut être appliqué qu’aux commandes parentes d’abonnement " +"qui contiennent un produit avec des frais d’inscription." + +#: includes/class-wc-subscriptions-coupon.php:505 +msgid "" +"Sorry, recurring coupons can only be applied to subscriptions or " +"subscription orders." +msgstr "" +"Désolé, les codes promo récurrents ne peuvent être appliqués qu’à des " +"abonnements ou des commandes d’abonnement." + +#: includes/class-wc-subscriptions-cart.php:1240 +msgid "Invalid recurring shipping method." +msgstr "Méthode de livraison récurrente non valide." + +#: includes/class-wc-subscription.php:2462 +#: includes/class-wc-subscriptions-checkout.php:343 +msgid "Backordered" +msgstr "En cours d’approvisionnement" + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2410 +msgid "The %s date must occur after the cancellation date." +msgstr "La date de %s doit être postérieure à la date d’annulation." + +#. translators: %d: subscription ID. +#. translators: %d: order ID. +#: includes/class-wc-subscription.php:1343 +#: includes/class-wc-subscription.php:2442 +msgid "Subscription #%d: " +msgstr "Abonnement n° %d :" + +#: includes/class-wc-subscription.php:1213 +msgid "Not cancelled" +msgstr "Pas annulé" + +#. translators: %s: new order status +#: includes/class-wc-subscription.php:590 +msgid "Status set to %s." +msgstr "État défini sur %s." + +#. translators: 1: subscription status, 2: error message. +#: includes/class-wc-subscription.php:546 +msgid "Unable to change subscription status to \"%1$s\". Exception: %2$s" +msgstr "" +"Impossible de modifier l’état d’abonnement sur « %1$s ». Exception : %2$s" + +#. translators: placeholder is an error message. +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:242 +msgid "Cannot create subscription: %s." +msgstr "Impossible de créer l’abonnement : %s." + +#: includes/api/class-wc-rest-subscriptions-controller.php:541 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:388 +msgid "The subscription's end date." +msgstr "Date de fin de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:536 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:383 +msgid "The subscription's next payment date." +msgstr "Date du prochain paiement de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:531 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:378 +msgid "The subscription's trial date" +msgstr "Date d’essai de l’abonnement" + +#: includes/api/class-wc-rest-subscriptions-controller.php:526 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:373 +msgid "The subscription's start date." +msgstr "Date de début de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:519 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:366 +msgid "Payment gateway ID." +msgstr "ID de la passerelle de paiement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:514 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:361 +msgid "Subscription payment details." +msgstr "Détails de paiement de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:508 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:355 +msgid "Billing period for the subscription." +msgstr "Période de facturation de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:503 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:350 +msgid "The number of billing periods between subscription renewals." +msgstr "" +"Nombre de périodes de facturation entre les renouvellements d’abonnement." + +#. translators: placeholder is an error message. +#: includes/api/class-wc-rest-subscriptions-controller.php:472 +#: includes/api/class-wc-rest-subscriptions-controller.php:778 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:287 +msgid "Updating subscription dates errored with message: %s" +msgstr "Erreur de mise à jour des dates d’abonnement avec le message : %s" + +#. translators: 1$: gateway id, 2$: error message +#: includes/api/class-wc-rest-subscriptions-controller.php:402 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336 +msgid "" +"Subscription payment method could not be set to %1$s with error message: %2$s" +msgstr "" +"Le moyen de paiement de l’abonnement n’a pas pu être défini sur %1$s avec le " +"message d’erreur : %2$s" + +#: includes/api/class-wc-rest-subscriptions-controller.php:184 +msgid "Customer ID is invalid." +msgstr "L’ID client est non valide." + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:256 +msgid "Renewals amount" +msgstr "Montant des renouvellements" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:247 +msgid "Renewals count" +msgstr "Nombre de renouvellements" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:182 +msgid "Next 7 Days" +msgstr "7 prochains jours" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:181 +msgid "Next Month" +msgstr "Mois suivant" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:180 +msgid "Next 30 Days" +msgstr "30 prochains jours" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:179 +msgid "Next 12 Months" +msgstr "12 prochains mois" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:103 +msgid "%s average renewal amount" +msgstr "%s montant de renouvellement moyen" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:89 +msgid "%s renewal income in this period" +msgstr "%s revenus de renouvellement sur cette période" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:295 +msgid "Recovered Renewal Revenue" +msgstr "Revenu de renouvellement récupéré" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:279 +msgid "Pending retries" +msgstr "Nouvelles tentatives en attente" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:263 +msgid "Failed retries" +msgstr "Nouvelles tentatives échouées" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:247 +msgid "Successful retries" +msgstr "Nouvelles tentatives réussies" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:145 +msgid "The number of renewal payment retries not yet processed." +msgstr "" +"Nombre de nouvelles tentatives de renouvellement de paiement non encore " +"traitées." + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:144 +msgid "%s retry attempts pending" +msgstr "%s nouvelles tentatives en attente" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:137 +msgid "" +"The number of renewal payment retries for this period which did not result " +"in a successful payment." +msgstr "" +"Nombre de nouvelles tentatives de paiement de renouvellement pour cette " +"période qui n’ont pas abouti à un paiement réussi." + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:136 +msgid "%s retry attempts failed" +msgstr "%s nouvelles tentatives échouées" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:129 +msgid "" +"The number of renewal payment retries for this period which were able to " +"process the payment which had previously failed one or more times." +msgstr "" +"Nombre de nouvelles tentatives de paiement de renouvellement pour cette " +"période qui ont pu traiter le paiement qui avait échoué précédemment une ou " +"plusieurs fois." + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:128 +msgid "%s retry attempts succeeded" +msgstr "%s nouvelles tentatives réussies" + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:122 +msgid "" +"The number of renewal orders which had a failed payment use the retry system." +msgstr "" +"Nombre de commandes de renouvellement dont le paiement échoué utilise le " +"système de nouvelle tentative." + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:121 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:96 +msgid "%s renewal orders" +msgstr "%s commandes de renouvellement" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:114 +msgid "" +"The total amount of revenue, including tax and shipping, recovered with the " +"failed payment retry system for renewal orders with a failed payment." +msgstr "" +"Montant total des revenus, y compris les frais d’expédition et de taxe, " +"récupéré avec le système de nouvelle tentative de paiement échoué pour les " +"commandes de renouvellement avec un paiement échoué." + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:113 +msgid "%s renewal revenue recovered" +msgstr "%s revenu de renouvellement récupéré" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:1004 +msgid "Renewal Totals" +msgstr "Totaux de renouvellements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:984 +msgid "Resubscribe Totals" +msgstr "Totaux de réabonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:964 +msgid "Signup Totals" +msgstr "Totaux d’inscriptions" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:949 +msgid "Cancellations" +msgstr "Annulations" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:901 +msgid "Number of renewals" +msgstr "Nombre de renouvellements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:886 +msgid "Number of resubscribes" +msgstr "Nombre de réabonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:871 +msgid "Subscriptions signups" +msgstr "Inscriptions d’abonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:839 +msgid "Switched subscriptions" +msgstr "Abonnements changés" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:780 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:199 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:213 +msgid "Export CSV" +msgstr "Exporter un CSV" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:735 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:162 +msgid "Last 7 Days" +msgstr "7 derniers jours" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:734 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:161 +msgid "This Month" +msgstr "Ce mois-ci" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:733 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:160 +msgid "Last Month" +msgstr "Mois dernier" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:732 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:159 +msgid "Year" +msgstr "Année" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:718 +msgid "Change in subscriptions between the start and end of the period." +msgstr "Changement des abonnements entre le début et la fin de la période." + +#. translators: %s: subscription net loss (with percentage). +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:713 +msgid "%s net subscription loss" +msgstr "%s perte nette d’abonnement" + +#. translators: %s: subscription net gain (with percentage). +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:710 +msgid "%s net subscription gain" +msgstr "%s gain net d’abonnement" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:693 +msgid "" +"The number of subscriptions during this period with an end date in the " +"future and a status other than pending." +msgstr "" +"Nombre d’abonnements pendant cette période avec une date de fin dans le " +"futur et un état autre que en attente." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:667 +msgid "" +"The number of subscriptions which have either expired or reached the end of " +"the prepaid term if it was previously cancelled." +msgstr "" +"Nombre d’abonnements qui ont expiré ou ont atteint la fin du terme prépayé " +"s’il était précédemment annulé." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:645 +msgid "" +"The number of subscriptions cancelled by the customer or store manager " +"during this period. The pre-paid term may not yet have ended during this " +"period." +msgstr "" +"Nombre d’abonnements annulés par le client ou le gérant de la boutique " +"pendant cette période. Le terme prépayé peut ne pas être encore terminé " +"pendant cette période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:623 +msgid "" +"The number of subscriptions upgraded, downgraded or cross-graded during this " +"period." +msgstr "" +"Nombre d’abonnements mis à niveau, rétrogradés ou reclassés pendant cette " +"période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:601 +msgid "The number of renewal orders processed during this period." +msgstr "Nombre de commandes de renouvellement traitées pendant cette période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:579 +msgid "The number of resubscribe orders processed during this period." +msgstr "Nombre de commandes de réabonnement traitées pendant cette période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:557 +msgid "" +"The number of subscriptions purchased in parent orders created during this " +"period. This represents the new subscriptions created by customers placing " +"an order via checkout." +msgstr "" +"Nombre d’abonnements achetés dans les commandes parentes créées pendant " +"cette période. Cela représente les nouveaux abonnements créés par les " +"clients passant une commande via la validation de commande." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:505 +msgid "The sum of all resubscribe orders including tax and shipping." +msgstr "" +"Somme de toutes les commandes de réabonnement, incluant les frais " +"d’expédition et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:504 +msgid "%s resubscribe revenue in this period" +msgstr "%s revenu de réabonnement sur cette période" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:497 +msgid "The sum of all renewal orders including tax and shipping." +msgstr "" +"Somme de toutes les commandes de renouvellement, incluant les frais " +"d’expédition et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:496 +msgid "%s renewal revenue in this period" +msgstr "%s revenu de renouvellement sur cette période" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:489 +msgid "" +"The sum of all subscription parent orders, including other items, fees, tax " +"and shipping." +msgstr "" +"Somme de toutes les commandes parentes d’abonnement, incluant d’autres " +"articles, les frais, les frais d’expédition et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:488 +msgid "%s signup revenue in this period" +msgstr "%s revenu d’inscription sur cette période" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:300 +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:340 +msgid "subscriptions" +msgstr "abonnements" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:95 +msgid "The average line total on all orders for this product line item." +msgstr "" +"Total moyen de la ligne pour toutes les commandes de cet article dans la " +"ligne de produit." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:95 +msgid "Average Lifetime Value %s" +msgstr "Valeur moyenne de la durée de vie %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:93 +msgid "The average line total for this product on each subscription." +msgstr "Total moyen de la ligne pour ce produit sur chaque abonnement." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:93 +msgid "Average Recurring Line Total %s" +msgstr "Total moyen de la ligne récurrente %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:91 +msgid "" +"The number of subscriptions that include this product as a line item and " +"have a status other than pending or trashed." +msgstr "" +"Nombre d’abonnements qui incluent ce produit en tant qu'article de la ligne " +"et dont l’état n’est pas en attente ou déplacé vers la corbeille." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:91 +msgid "Subscription Count %s" +msgstr "Nombre d’abonnements %s" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:89 +msgid "Subscription Product" +msgstr "Produit d’abonnement" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:30 +msgid "No products found." +msgstr "Aucun produit trouvé." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:105 +msgid "The total value of this customer's sign-up, switch and renewal orders." +msgstr "" +"Valeur totale des commandes d’inscription, de changement et de " +"renouvellement de ce client." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:105 +msgid "Lifetime Value from Subscriptions %s" +msgstr "Valeur à vie des abonnements %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:103 +msgid "" +"The number of sign-up, switch and renewal orders this customer has placed " +"with your store with a paid status (i.e. processing or complete)." +msgstr "" +"Nombre des commandes d’inscription, de changement et de renouvellement " +"placées par ce client avec votre boutique avec un état payé (c.-à-d. en " +"cours de traitement ou terminé)." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:103 +msgid "Total Subscription Orders %s" +msgstr "Total des commandes d’abonnement %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:101 +msgid "" +"The number of subscriptions this customer has with a status other than " +"pending or trashed." +msgstr "" +"Nombre d’abonnements de ce client avec un état autre que en attente ou " +"déplacé vers la corbeille." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:101 +msgid "Total Subscriptions %s" +msgstr "Total des abonnements %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:99 +msgid "" +"The number of subscriptions this customer has with a status of active or " +"pending cancellation." +msgstr "" +"Nombre d’abonnements de ce client avec un état d’annulation active ou en " +"attente." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:99 +msgid "Active Subscriptions %s" +msgstr "Abonnements actifs %s" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:48 +msgid "Average Lifetime Value" +msgstr "Valeur moyenne de la durée de vie" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:47 +msgid "Total Subscription Orders" +msgstr "Total des commandes d’abonnement" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:46 +msgid "Total Subscriptions" +msgstr "Total des abonnements" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:45 +msgid "Active Subscriptions" +msgstr "Abonnements actifs" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:44 +msgid "Total Subscribers" +msgstr "Total des abonnés" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:32 +msgid "No customers found." +msgstr "Aucun client." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:23 +msgid "Customers" +msgstr "Clients" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:22 +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:97 +msgid "Customer" +msgstr "Client" + +#: includes/admin/reports/class-wcs-report-retention-rate.php:226 +msgid "Unended Subscription Count" +msgstr "Nombre d’abonnements non terminés" + +#. translators: %d refers to the number of times we have detected cache update +#. failures +#: includes/admin/reports/class-wcs-report-cache-manager.php:323 +msgid "%d failures" +msgid_plural "%d failure" +msgstr[0] "%d échecs" +msgstr[1] "%d échec" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:320 +msgid "Cache Update Failures" +msgstr "Échecs de mise à jour du cache" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:265 +msgid "" +"Please note: data for this report is cached. The data displayed may be out " +"of date by up to 24 hours. The cache is updated each morning at 4am in your " +"site's timezone." +msgstr "" +"Veuillez noter : les données de ce rapport sont mises en cache. Les données " +"affichées peuvent être obsolètes jusqu’à 24 heures. Le cache est mis à jour " +"chaque matin à 4 h dans le fuseau horaire de votre site." + +#: includes/admin/meta-boxes/views/html-retries-table.php:32 +msgid "" +"The email sent to the customer when the renewal payment or payment retry " +"failed to notify them that the payment would be retried." +msgstr "" +"E-mail envoyé au client lorsque le paiement de renouvellement ou la nouvelle " +"tentative de paiement n’a pas pu l’informer que le paiement serait retenté." + +#: includes/admin/meta-boxes/views/html-retries-table.php:28 +msgid "" +"The status applied to the subscription for the time between when the renewal " +"payment failed or last retry occurred and when this retry was processed." +msgstr "" +"État appliqué à l’abonnement pour le temps écoulé entre l’échec du paiement " +"de renouvellement ou la dernière tentative et le traitement de cette " +"nouvelle tentative." + +#: includes/admin/meta-boxes/views/html-retries-table.php:27 +msgid "Status of Subscription" +msgstr "État de l’abonnement" + +#: includes/admin/meta-boxes/views/html-retries-table.php:24 +msgid "" +"The status applied to the order for the time between when the renewal " +"payment failed or last retry occurred and when this retry was processed." +msgstr "" +"État appliqué à la commande pour le temps écoulé entre l’échec du paiement " +"de renouvellement ou la dernière tentative et le traitement de cette " +"nouvelle tentative." + +#: includes/admin/meta-boxes/views/html-retries-table.php:23 +msgid "Status of Order" +msgstr "État de la commande" + +#: includes/admin/meta-boxes/views/html-retries-table.php:20 +msgid "" +"The status of the automatic payment retry: pending means the retry will be " +"processed in the future, failed means the payment was not successful when " +"retried and completed means the payment succeeded when retried." +msgstr "" +"État de la nouvelle tentative de paiement automatique : en attente signifie " +"que la nouvelle tentative sera traitée à l’avenir, échoué signifie que le " +"paiement a échoué lors de la nouvelle tentative et terminé signifie que le " +"paiement a réussi lors de la nouvelle tentative." + +#: includes/admin/meta-boxes/views/html-retries-table.php:19 +msgid "Retry Status" +msgstr "État de la nouvelle tentative" + +#: includes/admin/meta-boxes/views/html-retries-table.php:17 +msgid "Retry Date" +msgstr "Date de la nouvelle tentative" + +#. translators: placeholder is error message from the payment gateway or +#. subscriptions when updating the status +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:401 +msgid "Error updating some information: %s" +msgstr "Erreur lors de la mise à jour de certaines informations : %s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:264 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:294 +msgid "Customer Provided Note" +msgstr "Note fournie par le client" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:231 +msgid "Load shipping address" +msgstr "Charger l’adresse de livraison" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:140 +msgid "Load billing address" +msgstr "Charger l’adresse de facturation" + +#. Author of the plugin +#: includes/admin/class-wcs-admin-reports.php:104 +#: includes/admin/reports/class-wcs-report-cache-manager.php:262 +msgid "WooCommerce" +msgstr "WooCommerce" + +#: includes/admin/class-wcs-admin-reports.php:83 +msgid "Failed Payment Retries" +msgstr "Nouvelles tentatives de paiement échouées" + +#: includes/admin/class-wcs-admin-reports.php:73 +msgid "Subscriptions by Customer" +msgstr "Abonnements par client" + +#: includes/admin/class-wcs-admin-reports.php:67 +msgid "Subscriptions by Product" +msgstr "Abonnements par produit" + +#: includes/admin/class-wcs-admin-reports.php:61 +msgid "Retention Rate" +msgstr "Taux de conservation" + +#: includes/admin/class-wcs-admin-reports.php:55 +msgid "Upcoming Recurring Revenue" +msgstr "Revenus récurrents à venir" + +#: includes/admin/class-wcs-admin-reports.php:49 +msgid "Subscription Events by Date" +msgstr "Événements d’abonnement par date" + +#. translators: 1: user display name 2: user ID 3: user email +#: includes/admin/class-wcs-admin-post-types.php:1107 +msgid "%1$s (#%2$s – %3$s)" +msgstr "%1$s (n°%2$s – %3$s)" + +#: includes/admin/class-wcs-admin-post-types.php:654 +msgid "" +"This date should be treated as an estimate only. The payment gateway for " +"this subscription controls when payments are processed." +msgstr "" +"Cette date ne doit être considérée que comme une estimation. La passerelle " +"de paiement pour cet abonnement contrôle le moment où les paiements sont " +"traités." + +#: includes/admin/class-wcs-admin-post-types.php:651 +msgid "Y/m/d g:i:s A" +msgstr "" +"d/m/Y à G h i mi\n" +" s s" + +#: includes/admin/class-wcs-admin-post-types.php:569 +msgid "Show more details" +msgstr "Afficher plus de détails" + +#: includes/admin/class-wcs-admin-post-types.php:429 +msgid "Last Order Date" +msgstr "Date de la dernière commande" + +#: includes/admin/class-wcs-admin-meta-boxes.php:187 +msgid "Retry Renewal Payment" +msgstr "Retenter le paiement de renouvellement" + +#: includes/admin/class-wcs-admin-meta-boxes.php:144 +msgid "" +"Are you sure you want to retry payment for this renewal order?\n" +"\n" +"This will attempt to charge the customer and send renewal order emails (if " +"emails are enabled)." +msgstr "" +"Voulez-vous vraiment retenter le paiement pour cette commande de " +"renouvellement ?\n" +"\n" +"Cela tentera de facturer le client et d’envoyer des e-mails de commande de " +"renouvellement (si les e-mails sont activés)." + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1925 +msgid "" +"Payment gateways which don't support automatic recurring payments can be " +"used to process %1$smanual subscription renewal payments%2$s." +msgstr "" +"Les passerelles de paiement qui ne prennent pas en charge les paiements " +"récurrents automatiques peuvent être utilisées pour traiter les " +"%1$spaiements de renouvellement d’abonnement manuels%2$s." + +#: includes/admin/class-wc-subscriptions-admin.php:1917 +msgid "Recurring Payments" +msgstr "Paiements récurrents" + +#. translators: $1-2: opening and closing tags of a link that takes to Woo +#. marketplace / Stripe product page +#: includes/admin/class-wc-subscriptions-admin.php:1912 +msgid "" +"No payment gateways capable of processing automatic subscription payments " +"are enabled. If you would like to process automatic payments, we recommend " +"the %1$sfree Stripe extension%2$s." +msgstr "" +"Aucune passerelle de paiement capable de traiter les paiements d’abonnement " +"automatique n’est activée. Si vous voulez traiter les paiements automatiques," +" nous vous recommandons l’%1$sextension Stripe gratuite%2$s." + +#: includes/admin/class-wc-subscriptions-admin.php:1893 +msgid "" +"This subscription is no longer editable because the payment gateway does not " +"allow modification of recurring amounts." +msgstr "" +"Cet abonnement n’est plus modifiable car la passerelle de paiement " +"n’autorise pas la modification des montants récurrents." + +#: includes/admin/class-wc-subscriptions-admin.php:1889 +msgid "Subscription items can no longer be edited." +msgstr "Les articles d’abonnement ne peuvent plus être modifiés." + +#: includes/admin/class-wc-subscriptions-admin.php:1335 +msgid "" +"Allow a subscription product to be purchased with other products and " +"subscriptions in the same transaction." +msgstr "" +"Autoriser l’achat d’un produit d’abonnement avec d’autres produits et " +"abonnements dans la même transaction." + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1301 +msgid "" +"If you don't want new subscription purchases to automatically charge renewal " +"payments, you can turn off automatic payments. Existing automatic " +"subscriptions will continue to charge customers automatically. %1$sLearn " +"more%2$s." +msgstr "" +"Si vous ne souhaitez pas que les nouveaux achats d’abonnement facturent " +"automatiquement les paiements de renouvellement, vous pouvez désactiver les " +"paiements automatiques. Les abonnements automatiques existants continueront " +"de facturer les clients automatiquement. %1$sEn savoir plus%2$s." + +#. translators: %s: subscription status. +#: includes/admin/class-wc-subscriptions-admin.php:778 +msgid "" +"Unable to change subscription status to \"%s\". Please assign a customer to " +"the subscription to activate it." +msgstr "" +"Impossible de modifier l’état d’abonnement sur « %s ». Veuillez assigner un " +"client à l’abonnement pour l’activer." + +#: includes/admin/class-wc-subscriptions-admin.php:330 +msgid "" +"Automatically expire the subscription after this length of time. This length " +"is in addition to any free trial or amount of time provided before a " +"synchronised first renewal date." +msgstr "" +"Expire automatiquement l’abonnement après cette durée. Cette durée s’ajoute " +"à tout essai gratuit ou à toute durée accordée avant une première date de " +"renouvellement synchronisée." + +#: includes/admin/class-wc-subscriptions-admin.php:327 +#: includes/admin/class-wc-subscriptions-admin.php:451 +#: templates/admin/html-variation-price.php:66 +msgid "Expire after" +msgstr "Expire après" + +#: includes/admin/class-wc-subscriptions-admin.php:306 +msgid "Subscription interval" +msgstr "Intervalle d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:285 +msgid "Choose the subscription price, billing interval and period." +msgstr "" +"Choisissez le prix de l’abonnement, l’intervalle de facturation et la " +"période." + +#: tests/unit/scheduler/scheduler.php:66 wcs-functions.php:304 +msgctxt "table heading" +msgid "Trial End" +msgstr "Fin de l’essai" + +#: wcs-functions.php:277 +msgid "Can not get address type display name. Address type is not a string." +msgstr "" +"Impossible d’obtenir le nom d’affichage du type d’adresse. Le type d’adresse " +"n’est pas une chaîne." + +#. translators: placeholder is order date parsed by strftime +#: wcs-functions.php:163 +msgctxt "The post title for the new subscription" +msgid "Subscription – %s" +msgstr "Abonnement – %s" + +#: wcs-functions.php:142 +msgctxt "Error message while creating a subscription" +msgid "Invalid subscription customer_id." +msgstr "Abonnement non valide customer_id." + +#: wcs-functions.php:132 +msgctxt "Error message while creating a subscription" +msgid "Subscription created date must be before current day." +msgstr "" +"La date de création de l’abonnement doit être antérieure au jour en cours." + +#: wcs-functions.php:137 +msgctxt "Error message while creating a subscription" +msgid "" +"Invalid date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +msgstr "" +"Date non valide. La date doit être une chaîne au format : « Y-m-d H:i:s »." + +#: templates/single-product/add-to-cart/variable-subscription.php:23 +msgid "This product is currently out of stock and unavailable." +msgstr "Ce produit est actuellement en rupture et indisponible." + +#. translators: $1: formatted order total for the order, $2: number of items +#. bought +#: templates/myaccount/related-orders.php:56 +msgid "%1$s for %2$d item" +msgid_plural "%1$s for %2$d items" +msgstr[0] "%1$s pour %2$d article" +msgstr[1] "%1$s pour %2$d articles" + +#: templates/myaccount/my-subscriptions.php:46 +#: templates/myaccount/related-orders.php:53 +#: templates/myaccount/related-subscriptions.php:42 +msgctxt "Used in data attribute. Escaped" +msgid "Total" +msgstr "Total" + +#: templates/myaccount/my-subscriptions.php:40 +#: tests/unit/scheduler/scheduler.php:67 wcs-functions.php:305 +msgctxt "table heading" +msgid "Next Payment" +msgstr "Paiement suivant" + +#: tests/unit/scheduler/scheduler.php:70 wcs-functions.php:308 +msgctxt "table heading" +msgid "End Date" +msgstr "Date de fin" + +#: tests/unit/scheduler/scheduler.php:65 wcs-functions.php:303 +msgctxt "table heading" +msgid "Start Date" +msgstr "Date de début" + +#. translators: placeholder is localised start date +#: templates/emails/plain/subscription-info.php:29 +msgctxt "in plain emails for subscription information" +msgid "Start date: %s" +msgstr "" + +#. translators: placeholder is localised end date, or "when cancelled" +#: templates/emails/plain/subscription-info.php:33 +msgctxt "in plain emails for subscription information" +msgid "End date: %s" +msgstr "Date de fin : %s" + +#: templates/emails/plain/subscription-info.php:31 +msgctxt "Used as end date for an indefinite subscription" +msgid "When Cancelled" +msgstr "En cas d’annulation" + +#. translators: placeholder is the formatted order total for the subscription +#: templates/emails/plain/subscription-info.php:35 +msgctxt "in plain emails for subscription information" +msgid "Recurring price: %s" +msgstr "Prix récurrent : %s" + +#. translators: placeholder is subscription's number +#: templates/emails/plain/subscription-info.php:25 +msgctxt "in plain emails for subscription information" +msgid "Subscription: %s" +msgstr "Abonnement : %s" + +#: templates/emails/plain/cancelled-subscription.php:44 +#: templates/emails/plain/expired-subscription.php:44 +#: templates/emails/plain/on-hold-subscription.php:40 +msgctxt "in plain emails for subscription information" +msgid "View Subscription: %s" +msgstr "Afficher l’abonnement : %s" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, +#. note: no full stop due to url at the end +#: templates/emails/customer-renewal-invoice.php:31 +#: templates/emails/plain/customer-renewal-invoice.php:23 +msgctxt "In customer renewal invoice email" +msgid "" +"The automatic payment to renew your subscription with %1$s has failed. To " +"reactivate the subscription, please log in and pay for the renewal from your " +"account page: %2$s" +msgstr "" +"Le paiement automatique pour renouveler votre abonnement avec %1$s a échoué. " +"Pour réactiver l’abonnement, veuillez vous connecter et payer le " +"renouvellement sur la page de votre compte : %2$s" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, +#. note: no full stop due to url at the end +#: templates/emails/customer-renewal-invoice.php:22 +#: templates/emails/plain/customer-renewal-invoice.php:20 +msgctxt "In customer renewal invoice email" +msgid "" +"An order has been created for you to renew your subscription on %1$s. To pay " +"for this invoice please use the following link: %2$s" +msgstr "" +"Une commande a été créée pour vous afin de renouveler votre abonnement sur " +"%1$s. Pour payer cette facture, veuillez utiliser le lien suivant : %2$s" + +#: templates/emails/cancelled-subscription.php:24 +msgctxt "table headings in notification email" +msgid "End of Prepaid Term" +msgstr "Fin du terme prépayé" + +#: templates/myaccount/my-subscriptions.php:23 +#: templates/myaccount/related-subscriptions.php:23 +#: templates/myaccount/related-subscriptions.php:39 +msgctxt "table heading" +msgid "Next payment" +msgstr "Paiement suivant" + +#. translators: $1: customer's first name and last name, $2: how many +#. subscriptions customer switched +#: templates/emails/admin-new-switch-order.php:18 +#: templates/emails/plain/admin-new-switch-order.php:18 +msgctxt "Used in switch notification admin email" +msgid "" +"Customer %1$s has switched their subscription. The details of their new " +"subscription are as follows:" +msgid_plural "" +"Customer %1$s has switched %2$d of their subscriptions. The details of their " +"new subscriptions are as follows:" +msgstr[0] "" +"Le client %1$s a changé son abonnement. Les détails de son nouvel abonnement " +"sont les suivants :" +msgstr[1] "" +"Le client %1$s a changé %2$d de ses abonnements. Les détails de ses nouveaux " +"abonnements sont les suivants :" + +#: templates/emails/cancelled-subscription.php:22 +#: templates/emails/email-order-details.php:38 +#: templates/emails/expired-subscription.php:22 +#: templates/emails/on-hold-subscription.php:22 +msgctxt "table headings in notification email" +msgid "Price" +msgstr "Prix" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/admin-new-renewal-order.php:16 +#: templates/emails/plain/admin-new-renewal-order.php:16 +msgctxt "Used in admin email: new renewal order" +msgid "" +"You have received a subscription renewal order from %1$s. Their order is as " +"follows:" +msgstr "" +"Vous avez reçu une commande de renouvellement d’abonnement de %1$s. Voici sa " +"commande :" + +#: templates/checkout/form-change-payment-method.php:47 +msgctxt "text on button on checkout page" +msgid "Change payment method" +msgstr "Modifier le moyen de paiement" + +#: templates/checkout/form-change-payment-method.php:22 +msgctxt "table headings in notification email" +msgid "Totals" +msgstr "Totaux" + +#: templates/checkout/form-change-payment-method.php:21 +#: templates/emails/email-order-details.php:37 +msgctxt "table headings in notification email" +msgid "Quantity" +msgstr "Quantité" + +#: templates/checkout/form-change-payment-method.php:20 +#: templates/emails/email-order-details.php:36 +#: templates/myaccount/subscription-totals-table.php:21 +msgctxt "table headings in notification email" +msgid "Product" +msgstr "Produit" + +#: templates/admin/html-variation-price.php:31 +msgid "Subscription trial period:" +msgstr "Période d’essai d’abonnement :" + +#: templates/admin/deprecated/html-variation-price.php:59 +msgctxt "" +"Edit product screen, between the Billing Period and Subscription Length " +"dropdowns" +msgid "for" +msgstr "pour" + +#: includes/wcs-time-functions.php:191 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "year" +msgid_plural "years" +msgstr[0] "année" +msgstr[1] "années" + +#: includes/wcs-time-functions.php:190 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "month" +msgid_plural "months" +msgstr[0] "mois" +msgstr[1] "mois" + +#: includes/wcs-time-functions.php:189 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "week" +msgid_plural "weeks" +msgstr[0] "semaine" +msgstr[1] "semaines" + +#: includes/wcs-time-functions.php:188 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "day" +msgid_plural "days" +msgstr[0] "jour" +msgstr[1] "jours" + +#. translators: period interval, placeholder is ordinal (eg "$10 every +#. _2nd/3rd/4th_", etc) +#: includes/wcs-time-functions.php:163 +msgctxt "period interval with ordinal number (e.g. \"every 2nd\"" +msgid "every %s" +msgstr "chaque %s" + +#: includes/wcs-time-functions.php:105 +msgctxt "Subscription lengths. e.g. \"For 1 year...\"" +msgid "1 year" +msgstr "1 an" + +#: includes/wcs-time-functions.php:101 +msgctxt "Subscription lengths. e.g. \"For 1 month...\"" +msgid "1 month" +msgstr "1 mois" + +#: includes/wcs-time-functions.php:97 +msgctxt "Subscription lengths. e.g. \"For 1 week...\"" +msgid "1 week" +msgstr "1 semaine" + +#: includes/wcs-time-functions.php:93 +msgctxt "Subscription lengths. e.g. \"For 1 day...\"" +msgid "1 day" +msgstr "1 jour" + +#. translators: placeholder is number of years. (e.g. "Bill this every year / 4 +#. years") +#: includes/wcs-time-functions.php:37 +msgctxt "Subscription billing period." +msgid "year" +msgid_plural "%s years" +msgstr[0] "année" +msgstr[1] "%s années" + +#. translators: placeholder is number of months. (e.g. "Bill this every month +#. 4 months") +#: includes/wcs-time-functions.php:35 +msgctxt "Subscription billing period." +msgid "month" +msgid_plural "%s months" +msgstr[0] "mois" +msgstr[1] "%s mois" + +#. translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 +#. weeks") +#: includes/wcs-time-functions.php:33 +msgctxt "Subscription billing period." +msgid "week" +msgid_plural "%s weeks" +msgstr[0] "semaine" +msgstr[1] "%s semaines" + +#. translators: placeholder is number of days. (e.g. "Bill this every day / 4 +#. days") +#: includes/wcs-time-functions.php:31 +msgctxt "Subscription billing period." +msgid "day" +msgid_plural "%s days" +msgstr[0] "jour" +msgstr[1] "%s jours" + +#: includes/wcs-order-functions.php:152 +msgctxt "" +"Refers to the type of the copy being performed: \"copy_order\", " +"\"subscription\", \"renewal_order\", \"resubscribe_order\"" +msgid "Invalid data. Type of copy is not a string." +msgstr "Données non valides. Le type de copie n’est pas une chaîne." + +#: includes/wcs-order-functions.php:148 +msgctxt "" +"In wcs_copy_order_meta error message. Refers to origin and target order " +"objects." +msgid "Invalid data. Orders expected aren't orders." +msgstr "" +"Données non valides. Les commandes attendues ne sont pas des commandes." + +#: includes/upgrades/templates/wcs-about-2-0.php:121 +msgctxt "h3 on the About Subscriptions page for this new feature" +msgid "Change Payment Method" +msgstr "Modifier le moyen de paiement" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, +#. 4$: break tag +#: includes/upgrades/class-wc-subscriptions-upgrader.php:436 +msgctxt "" +"Error message that gets sent to front end when upgrading Subscriptions" +msgid "" +"Unable to repair subscriptions.%4$sError: %1$s%4$sPlease refresh the page " +"and try again. If problem persists, %2$scontact support%3$s." +msgstr "" +"Impossible de réparer les abonnements.%4$sErreur : %1$s%4$sVeuillez " +"rafraîchir la page et réessayer. Si le problème persiste, %2$scontactez " +"l’assistance%3$s." + +#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others +#. were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL +#. languages. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:417 +msgctxt "The assembled repair message that gets sent to front end." +msgid "%1$s%2$s %3$s" +msgstr "" + +#. translators: placeholder is "{execution_time}", which will be replaced on +#. front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:414 +msgctxt "Repair message that gets sent to front end." +msgid "(in %s seconds)" +msgstr "(en %s secondes)" + +#. translators: placeholder is number of subscriptions that were checked and +#. did not need repairs. There's a space at the beginning! +#: includes/upgrades/class-wc-subscriptions-upgrader.php:410 +msgctxt "Repair message that gets sent to front end." +msgid " %d other subscription was checked and did not need any repairs." +msgid_plural "" +"%d other subscriptions were checked and did not need any repairs." +msgstr[0] "" +" %d autre abonnement a été vérifié et ne nécessitait aucune réparation." +msgstr[1] "" +"%d autres abonnements ont été vérifiés et ne nécessitaient aucune réparation." + +#. translators: placeholder is the number of subscriptions repaired +#: includes/upgrades/class-wc-subscriptions-upgrader.php:404 +msgctxt "Repair message that gets sent to front end." +msgid "" +"Repaired %d subscriptions with incorrect dates, line tax data or missing " +"customer notes." +msgstr "" +"Réparation de %d abonnements avec des dates incorrectes, des données de " +"ligne de TVA ou des notes client manquantes." + +#. translators: placeholder is "{time_left}", will be replaced on front end +#. with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:379 +#: includes/upgrades/class-wc-subscriptions-upgrader.php:425 +msgctxt "Message that gets sent to front end." +msgid "Estimated time left (minutes:seconds): %s" +msgstr "Temps restant estimé (minutes:secondes) : %s" + +#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}", +#. will be replaced on front end with actual time it took +#: includes/upgrades/class-wc-subscriptions-upgrader.php:376 +msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)." +msgstr "" +"Migration de %1$s abonnements vers la nouvelle structure (en %2$s secondes)." + +#. translators: 1$: number of action scheduler hooks upgraded, 2$: +#. "{execution_time}", will be replaced on front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:364 +msgid "" +"Migrated %1$s subscription related hooks to the new scheduler (in %2$s " +"seconds)." +msgstr "" +"Migration de %1$s crochets liés à l’abonnement vers le nouveau planificateur " +"(en %2$s secondes)." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:275 +msgctxt "" +"when it is a payment change, and there is a subscr_signup message, this will " +"be a confirmation message that PayPal accepted it being the new payment " +"method" +msgid "IPN subscription payment method changed to PayPal." +msgstr "Le moyen de paiement d’abonnement IPN a été remplacé par PayPal." + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:150 +#: templates/admin/deprecated/order-shipping-html.php:14 +#: templates/admin/deprecated/order-tax-html.php:9 +msgctxt "no information about something" +msgid "N/A" +msgstr "ND" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:138 +msgctxt "used in api error message if there is no long message" +msgid "Unknown error" +msgstr "Erreur inconnue" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:136 +msgctxt "used in api error message if there is no severity code from PayPal" +msgid "Error" +msgstr "Erreur" + +#: includes/gateways/paypal/class-wcs-paypal.php:626 +msgctxt "" +"used in User Agent data sent to PayPal to help identify where a payment came " +"from" +msgid "WooCommerce Subscriptions PayPal" +msgstr "WooCommerce Subscriptions PayPal" + +#: includes/gateways/paypal/class-wcs-paypal.php:362 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:320 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:336 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:384 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:150 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:156 +msgctxt "" +"hash before the order number. Used as a character to remove from the actual " +"order number" +msgid "#" +msgstr "n°" + +#. translators: $1: {blogname}, $2: {order_date}, variables will be substituted +#. when email is sent out +#: includes/emails/class-wcs-email-completed-renewal-order.php:40 +msgctxt "Default email subject for email with downloadable files in it" +msgid "" +"Your %1$s subscription renewal order from %2$s is complete - download your " +"files" +msgstr "" +"Votre commande de renouvellement d’abonnement de %1$s du %2$s est terminée, " +"téléchargez vos fichiers" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:38 +msgctxt "Default email heading for email with downloadable files in it" +msgid "Your subscription renewal order is complete - download your files" +msgstr "" +"Votre commande de renouvellement d’abonnement est terminée, téléchargez vos " +"fichiers" + +#. translators: $1: {blogname}, $2: {order_date}, variables that will be +#. substituted when email is sent out +#: includes/emails/class-wcs-email-completed-renewal-order.php:31 +msgctxt "" +"Default email subject for email to customer on completed renewal order" +msgid "Your %1$s renewal order from %2$s is complete" +msgstr "Votre commande de renouvellement de %1$s du %2$s est terminée" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:29 +msgctxt "" +"Default email heading for email to customer on completed renewal order" +msgid "Your renewal order is complete" +msgstr "Votre commande de renouvellement est terminée" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:173 +#: includes/emails/class-wcs-email-expired-subscription.php:171 +#: includes/emails/class-wcs-email-on-hold-subscription.php:171 +msgctxt "text, html or multipart" +msgid "Email type" +msgstr "Type d’e-mail" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:165 +#: includes/emails/class-wcs-email-expired-subscription.php:163 +#: includes/emails/class-wcs-email-on-hold-subscription.php:163 +msgctxt "" +"Name the setting that controls the main heading contained within the email " +"notification" +msgid "Email Heading" +msgstr "En-tête de l’e-mail" + +#. translators: placeholder is {blogname}, a variable that will be substituted +#. when email is sent out +#: includes/emails/class-wcs-email-cancelled-subscription.php:31 +msgctxt "default email subject for cancelled emails sent to the admin" +msgid "[%s] Subscription Cancelled" +msgstr "[%s] Abonnement annulé" + +#: includes/class-wcs-user-change-status-handler.php:77 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been cancelled." +msgstr "Votre abonnement a été annulé." + +#: includes/class-wcs-user-change-status-handler.php:76 +msgctxt "order note left on subscription after user action" +msgid "Subscription cancelled by the subscriber from their account page." +msgstr "Abonnement annulé par l’abonné sur sa page de compte." + +#: includes/class-wcs-user-change-status-handler.php:68 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been put on hold." +msgstr "Votre abonnement a été mis en attente." + +#: includes/class-wcs-user-change-status-handler.php:67 +msgctxt "order note left on subscription after user action" +msgid "Subscription put on hold by the subscriber from their account page." +msgstr "Abonnement mis en attente par l’abonné sur sa page de compte." + +#: includes/class-wcs-user-change-status-handler.php:58 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been reactivated." +msgstr "Votre abonnement a été réactivé." + +#: includes/class-wcs-user-change-status-handler.php:57 +msgctxt "order note left on subscription after user action" +msgid "Subscription reactivated by the subscriber from their account page." +msgstr "Abonnement réactivé par l’abonné sur sa page de compte." + +#: includes/class-wcs-cart-renewal.php:676 +msgctxt "" +"Used in WooCommerce by removed item notification: \"_All linked subscription " +"items were_ removed. Undo?\" Filter for item title." +msgid "All linked subscription items were" +msgstr "Tous les articles d’abonnement liés étaient" + +#: includes/class-wc-subscriptions-synchroniser.php:319 +#: templates/admin/deprecated/html-variation-synchronisation.php:36 +#: templates/admin/html-variation-synchronisation.php:42 +msgctxt "input field placeholder for day field for annual subscriptions" +msgid "Day" +msgstr "Jour" + +#: includes/class-wc-subscriptions-switcher.php:433 +#: includes/class-wc-subscriptions-synchroniser.php:236 +msgctxt "when to prorate first payment / subscription length" +msgid "For All Subscription Products" +msgstr "Pour tous les produits d’abonnement" + +#. translators: $1: opening link tag, $2: order number, $3: closing link tag +#: includes/class-wc-subscriptions-order.php:1056 +msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s." +msgstr "Abonnement annulé pour la commande remboursée %1$sn°%2$s%3$s." + +#: includes/class-wc-subscriptions-manager.php:1079 +msgctxt "Subscription status" +msgid "On-hold" +msgstr "En attente" + +#: includes/class-wc-subscriptions-manager.php:1075 +msgctxt "Subscription status" +msgid "Failed" +msgstr "Échec" + +#: includes/class-wc-subscriptions-manager.php:87 +#: includes/class-wc-subscriptions-manager.php:1918 +#: includes/class-wc-subscriptions-manager.php:1936 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Subscription renewal payment due:" +msgstr "Paiement de renouvellement d’abonnement à régler :" + +#. translators: 1$: coupon code that is being removed +#: includes/class-wc-subscriptions-coupon.php:474 +msgid "Sorry, the \"%1$s\" coupon is only valid for renewals." +msgstr "" +"Désolé, le code promo « %1$s » n’est valide que pour les renouvellements." + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:213 +msgid "Error %d: Unable to add tax to subscription. Please try again." +msgstr "" +"Erreur %d : Impossible d’ajouter la TVA à l’abonnement. Veuillez réessayer." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:709 +#: includes/class-wc-subscriptions-change-payment-gateway.php:747 +msgctxt "the page title of the change payment method form" +msgid "Change payment method" +msgstr "Modifier le moyen de paiement" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:277 +msgctxt "label on button, imperative" +msgid "Change payment" +msgstr "Modifier le paiement" + +#. translators: placeholder is the formatted total to be paid for the +#. subscription wrapped in tags +#: templates/checkout/subscription-receipt.php:30 +msgid "Total: %s" +msgstr "Total : %s" + +#: includes/api/legacy/class-wc-api-subscriptions.php:613 +msgctxt "API response confirming order note deleted from a subscription" +msgid "Permanently deleted subscription note" +msgstr "Note d’abonnement supprimée définitivement" + +#. translators: placeholder is error message +#: includes/api/legacy/class-wc-api-subscriptions.php:276 +msgctxt "API error message when editing the order failed" +msgid "Edit subscription failed with error: %s" +msgstr "La modification de l’abonnement a échoué avec une erreur : %s" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:21 +#: templates/myaccount/my-subscriptions.php:24 +#: templates/myaccount/related-orders.php:25 +#: templates/myaccount/related-subscriptions.php:24 +#: templates/myaccount/subscription-totals-table.php:22 +msgctxt "table heading" +msgid "Total" +msgstr "Total" + +#. translators: $1: is opening link, $2: is subscription order number, $3: is +#. closing link tag, $4: is user's name +#: includes/admin/class-wcs-admin-post-types.php:565 +msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)" +msgid "%1$s#%2$s%3$s for %4$s" +msgstr "%1$sn°%2$s%3$s pour %4$s" + +#. translators: placeholder is customer's billing phone number +#: includes/admin/class-wcs-admin-post-types.php:537 +msgid "Tel: %s" +msgstr "Tél : %s" + +#. translators: placeholder is customer's billing email +#: includes/admin/class-wcs-admin-post-types.php:532 +msgid "Email: %s" +msgstr "E-mail : %s" + +#: includes/admin/class-wcs-admin-post-types.php:431 +msgctxt "number of orders linked to a subscription" +msgid "Orders" +msgstr "Commandes" + +#: includes/admin/class-wcs-admin-post-types.php:427 +msgid "Trial End" +msgstr "Fin de l’essai" + +#: includes/admin/class-wcs-admin-post-types.php:424 +msgid "Items" +msgstr "Articles" + +#: includes/admin/class-wcs-admin-post-types.php:335 +msgctxt "Used in order note. Reason why status changed." +msgid "Subscription status changed by bulk edit:" +msgstr "État d’abonnement modifié en lot :" + +#: includes/admin/class-wcs-admin-post-types.php:260 +#: includes/admin/class-wcs-admin-post-types.php:473 +#: includes/class-wc-subscriptions-manager.php:1854 +#: includes/wcs-user-functions.php:354 +#: templates/myaccount/related-orders.php:78 +msgctxt "an action on a subscription" +msgid "Cancel" +msgstr "Annuler" + +#: includes/admin/class-wcs-admin-post-types.php:258 +msgctxt "an action on a subscription" +msgid "Activate" +msgstr "Activer" + +#: includes/admin/class-wc-subscriptions-admin.php:1729 +#: includes/admin/class-wcs-admin-system-status.php:107 +msgctxt "Live or Staging, Label on WooCommerce -> System Status page" +msgid "Subscriptions Mode" +msgstr "Mode d’abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:864 +msgid "" +"Warning: Deleting a user will also delete the user's subscriptions. The " +"user's orders will remain but be reassigned to the 'Guest' user.\n" +"\n" +"Do you want to continue to delete this user and any associated subscriptions?" +msgstr "" +"Attention : supprimer un utilisateur supprimera également les abonnements de " +"cet utilisateur. Les commandes de l’utilisateur resteront mais seront " +"réaffectées à l’utilisateur « Invité ».\n" +"\n" +"Voulez-vous continuer et supprimer cet utilisateur et les abonnements " +"associés ?" + +#. translators: placeholder is trial period validation message if passed an +#. invalid value (e.g. "Trial period can not exceed 4 weeks") +#: templates/admin/deprecated/html-variation-price.php:118 +#: templates/admin/html-variation-price.php:27 +msgctxt "Trial period dropdown's description in pricing fields" +msgid "" +"An optional period of time to wait before charging the first recurring " +"payment. Any sign up fee will still be charged at the outset of the " +"subscription. %s" +msgstr "" +"Une période d’attente facultative avant de facturer le premier paiement " +"récurrent. Les frais d’inscription seront toujours facturés au début de " +"l’abonnement. %s" + +#. Description of the plugin +msgid "" +"Sell products and services with recurring payments in your WooCommerce Store." +msgstr "" +"Vendez des produits et des services avec des paiements récurrents dans votre " +"boutique WooCommerce." + +#. Plugin Name of the plugin +#: includes/privacy/class-wcs-privacy.php:40 +msgid "WooCommerce Subscriptions" +msgstr "Abonnements WooCommerce" + +#. translators: opening/closing tags - linked to ticket form. +#: woocommerce-subscriptions.php:1251 +msgid "" +"Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer " +"immediately. If you need assistance, after upgrading to Subscriptions v2.0, " +"please %1$sopen a support ticket%2$s." +msgstr "" +"Veuillez mettre à niveau l’extension WooCommerce Subscriptions vers la " +"version 2.0 ou plus récente immédiatement. Si vous avez besoin d’aide, après " +"la mise à niveau vers Subscriptions v2.0, veuillez %1$souvrir un ticket " +"d’assistance%2$s." + +#. translators: placeholder is Subscriptions version number. +#: woocommerce-subscriptions.php:1249 +msgid "" +"Warning! You are running version %s of WooCommerce Subscriptions plugin code " +"but your database has been upgraded to Subscriptions version 2.0. This will " +"cause major problems on your store." +msgstr "" +"Attention ! Vous exécutez la version %s du code d’extension WooCommerce " +"Subscriptions, mais votre base de données a été mise à niveau vers " +"Subscriptions version 2.0. Cela entraînera des problèmes majeurs sur votre " +"boutique." + +#. translators: placeholders are opening and closing tags. Leads to docs on +#. version 2 +#: woocommerce-subscriptions.php:1233 +msgid "" +"Warning! Version 2.0 is a major update to the WooCommerce Subscriptions " +"extension. Before updating, please create a backup, update all WooCommerce " +"extensions and test all plugins, custom code and payment gateways with " +"version 2.0 on a staging site. %1$sLearn more about the changes in version 2." +"0 »%2$s" +msgstr "" +"Attention ! La version 2.0 est une mise à jour majeure de l’extension " +"WooCommerce Subscriptions. Avant la mise à jour, veuillez créer une " +"sauvegarde, mettre à jour toutes les extensions WooCommerce et tester toutes " +"les extensions, le code personnalisé et les passerelles de paiement avec la " +"version 2.0 sur un site de préproduction. %1$sEn savoir plus sur les " +"modifications dans la version 2.0 »%2$s" + +#: woocommerce-subscriptions.php:1150 +msgid "Support" +msgstr "Forums de support" + +#: includes/upgrades/templates/wcs-about-2-0.php:36 +#: woocommerce-subscriptions.php:1149 +msgctxt "short for documents" +msgid "Docs" +msgstr "Documentations" + +#: woocommerce-subscriptions.php:944 +msgid "Enable automatic payments" +msgstr "Activer les paiements automatiques" + +#: woocommerce-subscriptions.php:939 +msgid "Quit nagging me (but don't enable automatic payments)" +msgstr "Ne plus me rappeler (mais ne pas activer les paiements automatiques)" + +#: woocommerce-subscriptions.php:761 +msgid "Variable Subscription" +msgstr "Abonnement variable" + +#. translators: 1$-2$: opening and closing tags, 3$: minimum supported +#. WooCommerce version, 4$-5$: opening and closing link tags, leads to plugin +#. admin +#: woocommerce-subscriptions.php:730 +msgid "" +"%1$sWooCommerce Subscriptions is inactive.%2$s This version of Subscriptions " +"requires WooCommerce %3$s or newer. Please %4$supdate WooCommerce to version " +"%3$s or newer »%5$s" +msgstr "" +"%1$sWooCommerce Subscriptions est inactif.%2$s Cette version de " +"Subscriptions requiert %3$s ou version plus récente. Veuillez %4$smettre à " +"jour WooCommerce vers la version %3$s ou plus récente »%5$s" + +#. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, +#. takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, +#. leads to plugins.php in admin +#: woocommerce-subscriptions.php:727 +msgid "" +"%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce " +"plugin%4$s must be active for WooCommerce Subscriptions to work. Please " +"%5$sinstall & activate WooCommerce »%6$s" +msgstr "" +"%1$sWooCommerce Subscriptions est inactif.%2$s L’%3$sextension " +"WooCommerce%4$s doit être active pour que WooCommerce Subscriptions " +"fonctionne. Veuillez %5$sinstaller et activer WooCommerce »%6$s" + +#. translators: placeholder is a number, numbers ending in 3 +#: woocommerce-subscriptions.php:688 +msgid "%srd" +msgstr "%se" + +#. translators: placeholder is a number, numbers ending in 2 +#: woocommerce-subscriptions.php:684 +msgid "%snd" +msgstr "%se" + +#. translators: placeholder is a number, numbers ending in 1 +#: woocommerce-subscriptions.php:680 +msgid "%sst" +msgstr "%ser" + +#. translators: placeholder is a number, this is for the teens +#. translators: placeholder is a number, numbers ending in 4-9, 0 +#: woocommerce-subscriptions.php:675 woocommerce-subscriptions.php:692 +msgid "%sth" +msgstr "%se" + +#: includes/class-wc-subscriptions-cart-validator.php:68 +#: woocommerce-subscriptions.php:535 +msgid "" +"A subscription has been removed from your cart. Products and subscriptions " +"can not be purchased at the same time." +msgstr "" +"Un abonnement a été supprimé de votre panier. Les produits et les " +"abonnements ne peuvent pas être achetés en même temps." + +#: includes/class-wc-subscriptions-cart-validator.php:62 +#: woocommerce-subscriptions.php:529 +msgid "" +"A subscription has been removed from your cart. Due to payment gateway " +"restrictions, different subscription products can not be purchased at the " +"same time." +msgstr "" +"Un abonnement a été supprimé de votre panier. En raison des restrictions de " +"la passerelle de paiement, différents produits d’abonnement ne peuvent pas " +"être achetés en même temps." + +#: includes/class-wc-subscriptions-cart-validator.php:56 +#: woocommerce-subscriptions.php:523 +msgid "" +"A subscription renewal has been removed from your cart. Multiple " +"subscriptions can not be purchased at the same time." +msgstr "" +"Un renouvellement d’abonnement a été supprimé de votre panier. Plusieurs " +"abonnements ne peuvent pas être achetés en même temps." + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:353 +msgctxt "post status label including post count" +msgid "Pending Cancellation (%s)" +msgid_plural "Pending Cancellation (%s)" +msgstr[0] "Annulation en attente (%s)" +msgstr[1] "Annulation en attente (%s)" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:351 +msgctxt "post status label including post count" +msgid "Expired (%s)" +msgid_plural "Expired (%s)" +msgstr[0] "Expiré (%s)" +msgstr[1] "Expiré (%s)" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:349 +msgctxt "post status label including post count" +msgid "Switched (%s)" +msgid_plural "Switched (%s)" +msgstr[0] "Changé (%s)" +msgstr[1] "Changé (%s)" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:347 +msgctxt "post status label including post count" +msgid "Active (%s)" +msgid_plural "Active (%s)" +msgstr[0] "Actif (%s)" +msgstr[1] "Actif (%s)" + +#. translators: placeholders are opening and closing link tags +#: woocommerce-subscriptions.php:332 +msgid "%1$sAdd a subscription product »%2$s" +msgstr "%1$sAjouter un produit d’abonnement »%2$s" + +#. translators: placeholders are opening and closing link tags +#: woocommerce-subscriptions.php:330 +msgid "%1$sLearn more about managing subscriptions »%2$s" +msgstr "%1$sEn savoir plus sur la gestion des abonnements »%2$s" + +#: woocommerce-subscriptions.php:328 +msgid "" +"Subscriptions will appear here for you to view and manage once purchased by " +"a customer." +msgstr "" +"Les abonnements apparaîtront ici pour que vous puissiez les consulter et les " +"gérer une fois achetés par un client." + +#: woocommerce-subscriptions.php:326 +msgid "No Subscriptions found" +msgstr "Aucun abonnement trouvé" + +#: woocommerce-subscriptions.php:281 +msgid "This is where subscriptions are stored." +msgstr "Il s’agit de l’emplacement de stockage des abonnements." + +#: woocommerce-subscriptions.php:278 +msgctxt "custom post type setting" +msgid "Parent Subscriptions" +msgstr "Abonnements parents" + +#: woocommerce-subscriptions.php:277 +msgctxt "custom post type setting" +msgid "No Subscriptions found in trash" +msgstr "Aucun abonnement trouvé dans la corbeille" + +#: woocommerce-subscriptions.php:273 woocommerce-subscriptions.php:274 +msgctxt "custom post type setting" +msgid "View Subscription" +msgstr "Afficher l’abonnement" + +#: woocommerce-subscriptions.php:272 +msgctxt "custom post type setting" +msgid "New Subscription" +msgstr "Nouvel abonnement" + +#: woocommerce-subscriptions.php:271 +msgctxt "custom post type setting" +msgid "Edit Subscription" +msgstr "Modifier l’abonnement" + +#: woocommerce-subscriptions.php:270 +msgctxt "custom post type setting" +msgid "Edit" +msgstr "Modifier" + +#: woocommerce-subscriptions.php:269 +msgctxt "custom post type setting" +msgid "Add New Subscription" +msgstr "Ajouter un nouvel abonnement" + +#: woocommerce-subscriptions.php:268 +msgctxt "custom post type setting" +msgid "Add Subscription" +msgstr "Ajouter un abonnement" + +#: wcs-functions.php:345 +msgid "Date type can not be an empty string." +msgstr "Le type de date ne peut pas être une chaîne vide." + +#: wcs-functions.php:343 +msgid "Date type is not a string." +msgstr "Le type de date n’est pas une chaîne." + +#: wcs-functions.php:254 +msgid "Can not get status name. Status is not a string." +msgstr "Impossible d’obtenir le nom de l’état. L’état n’est pas une chaîne." + +#: wcs-functions.php:238 +msgctxt "Subscription status" +msgid "Pending Cancellation" +msgstr "Annulation en attente" + +#: includes/class-wc-subscriptions-manager.php:1069 wcs-functions.php:237 +msgctxt "Subscription status" +msgid "Expired" +msgstr "Expiré" + +#: includes/class-wc-subscriptions-switcher.php:2704 wcs-functions.php:236 +msgctxt "Subscription status" +msgid "Switched" +msgstr "Changé" + +#: includes/class-wc-subscriptions-manager.php:1066 wcs-functions.php:235 +msgctxt "Subscription status" +msgid "Cancelled" +msgstr "Annulé" + +#: wcs-functions.php:234 +msgctxt "Subscription status" +msgid "On hold" +msgstr "En attente" + +#: includes/class-wc-subscriptions-manager.php:1063 wcs-functions.php:233 +msgctxt "Subscription status" +msgid "Active" +msgstr "Actif" + +#: includes/class-wc-subscriptions-manager.php:1072 wcs-functions.php:232 +msgctxt "Subscription status" +msgid "Pending" +msgstr "En attente" + +#: tests/unit/wcs_test_wcs_functions.php:833 +msgctxt "table column header" +msgid "Big Bang" +msgstr "Big Bang" + +#: templates/single-product/add-to-cart/subscription.php:32 +#: templates/single-product/add-to-cart/variable-subscription.php:30 +msgid "You have an active subscription to this product already." +msgstr "Vous avez déjà un abonnement actif à ce produit." + +#: includes/privacy/class-wcs-privacy-exporters.php:84 wcs-functions.php:283 +msgid "Shipping Address" +msgstr "Adresse de livraison" + +#: includes/privacy/class-wcs-privacy-exporters.php:83 wcs-functions.php:284 +msgid "Billing Address" +msgstr "Adresse de facturation" + +#: includes/admin/meta-boxes/views/html-retries-table.php:31 +msgid "Email" +msgstr "Adresse de messagerie" + +#. translators: placeholder is price string, denotes tax included in cart/order +#. total +#: includes/wcs-cart-functions.php:320 +msgctxt "includes tax" +msgid "(includes %s)" +msgstr "(inclut %s)" + +#: templates/myaccount/subscription-totals-table.php:35 +msgid "Are you sure you want remove this item from your subscription?" +msgstr "Voulez-vous vraiment supprimer cet article de votre abonnement ?" + +#: templates/myaccount/subscription-totals.php:23 +msgid "Subscription totals" +msgstr "Totaux des abonnements" + +#: templates/myaccount/subscription-details.php:100 +msgctxt "date on subscription updates list. Will be localized" +msgid "l jS \\o\\f F Y, h:ia" +msgstr "\\f F Y, h:ial jS \\o" + +#: templates/myaccount/subscription-details.php:94 +msgid "Subscription updates" +msgstr "Mises à jour des abonnements" + +#: templates/myaccount/subscription-details.php:81 +msgid "Actions" +msgstr "Actions" + +#: templates/myaccount/subscription-details.php:28 +msgctxt "customer subscription table header" +msgid "Trial end date" +msgstr "Date de fin d’essai" + +#: templates/myaccount/subscription-details.php:27 +msgctxt "customer subscription table header" +msgid "End date" +msgstr "Date de fin" + +#: templates/myaccount/subscription-details.php:26 +msgctxt "customer subscription table header" +msgid "Next payment date" +msgstr "Date du paiement suivant" + +#: templates/myaccount/subscription-details.php:25 +msgctxt "customer subscription table header" +msgid "Last order date" +msgstr "Date de la dernière commande" + +#: includes/class-wcs-template-loader.php:28 +msgid "My Account" +msgstr "Mon compte :" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:250 +#: includes/class-wcs-template-loader.php:28 +#: includes/wcs-helper-functions.php:286 +msgid "Invalid Subscription." +msgstr "Abonnement non valide." + +#: templates/myaccount/related-subscriptions.php:15 +msgid "Related subscriptions" +msgstr "Abonnements liés" + +#: templates/myaccount/my-subscriptions.php:50 +#: templates/myaccount/related-orders.php:84 +#: templates/myaccount/related-subscriptions.php:46 +msgctxt "view a subscription" +msgid "View" +msgstr "Voir" + +#: templates/myaccount/related-orders.php:65 +msgctxt "pay for a subscription" +msgid "Pay" +msgstr "Payer" + +#: templates/myaccount/related-orders.php:22 +msgid "Order" +msgstr "Ordre" + +#: includes/admin/class-wcs-admin-meta-boxes.php:79 +#: includes/admin/class-wcs-admin-meta-boxes.php:83 +msgid "Related Orders" +msgstr "Commandes similaires" + +#. translators: placeholder is the display name of a payment gateway a +#. subscription was paid by +#. translators: %s: payment method. +#: includes/admin/class-wcs-admin-post-types.php:609 +#: includes/class-wc-subscription.php:2025 +msgid "Via %s" +msgstr "Via %s" + +#: templates/myaccount/my-subscriptions.php:33 +#: templates/myaccount/related-subscriptions.php:31 +msgid "ID" +msgstr "ID" + +#: includes/admin/class-wcs-admin-post-types.php:428 +msgid "Next Payment" +msgstr "Paiement suivant" + +#: includes/admin/class-wcs-admin-post-types.php:430 +msgid "End Date" +msgstr "Date de fin" + +#: includes/admin/class-wcs-admin-post-types.php:426 +msgid "Start Date" +msgstr "Date de début" + +#: includes/class-wcs-query.php:296 +msgid "View subscription" +msgstr "Afficher l’abonnement" + +#: templates/emails/plain/subscription-info.php:20 +#: templates/emails/subscription-info.php:21 +msgid "Subscription information" +msgstr "Informations sur l’abonnement" + +#. translators: placeholder is subscription's view url +#: templates/emails/plain/customer-completed-switch-order.php:35 +msgid "View your subscription: %s" +msgstr "Afficher votre abonnement : %s" + +#. translators: placeholder is order's view url +#: templates/emails/plain/customer-completed-switch-order.php:24 +msgid "View your order: %s" +msgstr "Afficher votre commande : %s" + +#. translators: placeholder is localised date string +#: templates/emails/plain/cancelled-subscription.php:39 +msgid "End of Prepaid Term: %s" +msgstr "Fin du terme prépayé : %s" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/cancelled-subscription.php:16 +#: templates/emails/plain/cancelled-subscription.php:16 +msgid "" +"A subscription belonging to %1$s has been cancelled. Their subscription's " +"details are as follows:" +msgstr "" +"Un abonnement appartenant à %1$s a été annulé. Les détails de son abonnement " +"sont les suivants :" + +#. translators: placeholder is the subscription order number wrapped in +#. tags +#: templates/checkout/subscription-receipt.php:18 +#: templates/emails/plain/email-order-details.php:19 +msgid "Subscription Number: %s" +msgstr "Numéro d’abonnement : %s" + +#: templates/emails/plain/email-order-details.php:17 +msgid "Order date: %s" +msgstr "Date de la commande : %s" + +#: templates/emails/plain/email-order-details.php:16 +msgid "Order number: %s" +msgstr "Numéro de commande : %s" + +#: templates/emails/customer-renewal-invoice.php:24 +#: templates/emails/customer-renewal-invoice.php:33 +msgid "Pay Now »" +msgstr "Payer maintenant »" + +#: templates/emails/customer-completed-switch-order.php:18 +#: templates/emails/plain/customer-completed-switch-order.php:17 +msgid "" +"You have successfully changed your subscription items. Your new order and " +"subscription details are shown below for your reference:" +msgstr "" +"Vous avez modifié avec succès vos articles d’abonnement. Les détails de " +"votre nouvelle commande et de votre abonnement sont indiqués ci-dessous pour " +"votre référence :" + +#: includes/admin/class-wcs-admin-post-types.php:423 +#: templates/emails/cancelled-subscription.php:21 +#: templates/emails/expired-subscription.php:21 +#: templates/emails/on-hold-subscription.php:21 +#: templates/myaccount/my-subscriptions.php:21 +#: templates/myaccount/related-subscriptions.php:21 +#: woocommerce-subscriptions.php:267 +msgid "Subscription" +msgstr "Abonnement" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/expired-subscription.php:16 +#: templates/emails/plain/expired-subscription.php:16 +msgid "" +"A subscription belonging to %1$s has expired. Their subscription's details " +"are as follows:" +msgstr "" +"Un abonnement appartenant à %1$s a expiré. Les détails de son abonnement " +"sont les suivants :" + +#: templates/emails/admin-new-switch-order.php:28 +#: templates/emails/customer-completed-switch-order.php:26 +msgid "New subscription details" +msgstr "Détails du nouvel abonnement" + +#: templates/emails/admin-new-switch-order.php:20 +msgid "Switch Order Details" +msgstr "Détails de la commande de changement" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:43 +msgid "Customer Totals" +msgstr "Totaux des clients" + +#: includes/privacy/class-wcs-privacy-exporters.php:79 +msgid "Recurring Total" +msgstr "" + +#. translators: %s: shipping method label. +#: includes/wcs-cart-functions.php:97 includes/wcs-cart-functions.php:102 +msgid "Shipping via %s" +msgstr "Livraison via %s" + +#: templates/checkout/recurring-totals.php:31 +#: templates/checkout/recurring-totals.php:32 +msgid "Subtotal" +msgstr "Sous-total" + +#: templates/checkout/recurring-totals.php:151 +#: templates/checkout/recurring-totals.php:152 +msgid "Recurring total" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:82 +msgid "" +"Sorry, it seems no payment gateways support changing the recurring payment " +"method. Please contact us if you require assistance or to make alternate " +"arrangements." +msgstr "" +"Désolé, il semble qu’aucune passerelle de paiement ne prenne en charge la " +"modification du moyen de paiement récurrent. Veuillez nous contacter si vous " +"avez besoin d’aide ou si vous désirez mettre en place une alternative." + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:21 +msgid "Products" +msgstr "Produits" + +#: templates/admin/deprecated/order-tax-html.php:21 +msgid "Shipping Tax:" +msgstr "Taxe d’expédition :" + +#: templates/admin/deprecated/order-tax-html.php:17 +msgid "Recurring Sales Tax:" +msgstr "Taxes de vente récurrentes :" + +#: templates/admin/deprecated/order-shipping-html.php:34 +#: templates/admin/deprecated/order-shipping-html.php:36 +msgid "Other" +msgstr "Autre" + +#: templates/admin/deprecated/order-shipping-html.php:13 +msgid "Shipping Method" +msgstr "Méthode d’expédition" + +#: templates/admin/deprecated/order-shipping-html.php:8 +msgid "Label" +msgstr "Nom" + +#: templates/admin/html-variation-price.php:49 +msgid "Billing interval:" +msgstr "Intervalle de facturation :" + +#. translators: %s: currency symbol. +#. translators: placeholder is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:301 +#: templates/admin/html-variation-price.php:44 +msgid "Subscription price (%s)" +msgstr "Prix de l’abonnement (%s)" + +#: includes/admin/class-wc-subscriptions-admin.php:354 +#: templates/admin/html-variation-price.php:25 +msgid "Free trial" +msgstr "Essai gratuit" + +#. translators: %s is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:340 +#: templates/admin/html-variation-price.php:20 +msgid "Sign-up fee (%s)" +msgstr "Frais d’inscription (%s)" + +#: templates/admin/deprecated/html-variation-price.php:105 +msgctxt "example number of days / weeks / months" +msgid "e.g. 3" +msgstr "par ex. 3" + +#: includes/wcs-user-functions.php:345 +#: templates/single-product/add-to-cart/subscription.php:30 +#: templates/single-product/add-to-cart/variable-subscription.php:28 +msgid "Resubscribe" +msgstr "Se réabonner" + +#: includes/wcs-time-functions.php:210 +msgctxt "no trial period" +msgid "no" +msgstr "non" + +#: includes/wcs-time-functions.php:159 +msgctxt "period interval (eg \"$10 _every_ 2 weeks\")" +msgid "every" +msgstr "chaque" + +#: includes/wcs-order-functions.php:523 +msgid "Invalid data. No valid item id was passed in." +msgstr "" +"Données non valides. Aucun identifiant d’article valide n’a été transmis." + +#: includes/wcs-order-functions.php:519 +msgid "Invalid data. No valid subscription / order was passed in." +msgstr "" +"Données non valides. Aucun abonnement/commande valide n’a été transmis." + +#. translators: placeholder is an order type. +#: includes/wcs-order-functions.php:329 +msgid "\"%s\" is not a valid new order type." +msgstr "« %s » n’est pas un type de nouvelle commande valide." + +#: includes/wcs-order-functions.php:324 +msgid "$type passed to the function was not a string." +msgstr "$type transmis à la fonction n’était pas une chaîne." + +#. translators: placeholder is a date. +#: includes/wcs-order-functions.php:305 +msgid "Resubscribe Order – %s" +msgstr "Commande de réabonnement – %s" + +#. translators: placeholder is a date. +#: includes/wcs-order-functions.php:301 +msgid "Subscription Renewal Order – %s" +msgstr "Commande de renouvellement d’abonnement – %s" + +#. translators: placeholders are strftime() strings. +#. translators: Order date parsed by strftime +#: includes/wcs-order-functions.php:296 wcs-functions.php:161 +msgctxt "" +"Used in subscription post title. \"Subscription renewal order - \"" +msgid "%b %d, %Y @ %I:%M %p" +msgstr "%b %d, %Y à %I:%M %p" + +#. translators: minute placeholder for time input, javascript format +#: includes/wcs-helper-functions.php:48 +msgid "MM" +msgstr "MM" + +#. translators: hour placeholder for time input, javascript format +#: includes/wcs-helper-functions.php:45 +msgid "HH" +msgstr "HH" + +#. translators: date placeholder for input, javascript format +#: includes/wcs-helper-functions.php:40 +msgid "YYYY-MM-DD" +msgstr "AAAA-MM-JJ" + +#. translators: 1$: trial length (e.g. "3 weeks"), 2$: subscription string +#. (e.g. "$10 up front then $5 on March 23rd every 3rd year") +#: includes/wcs-formatting-functions.php:219 +msgid "%1$s free trial then %2$s" +msgstr "%1$s essai gratuit puis %2$s" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March +#. 23rd every 3rd year"), 2$: trial length (e.g. "3 weeks") +#: includes/wcs-formatting-functions.php:216 +msgid "%1$s after %2$s free trial" +msgstr "%1$s après l’essai gratuit de %2$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: subscription period (e.g. "month" or "3 months") +#: includes/wcs-formatting-functions.php:194 +msgid "%1$s %2$s then %3$s / %4$s" +msgid_plural "%1$s %2$s then %3$s every %4$s" +msgstr[0] "%1$s %2$s puis %3$s / %4$s" +msgstr[1] "%1$s %2$s puis %3$s chaque %4$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g. +#. "23rd"), 6$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:184 +msgid "%1$s %2$s then %3$s on %4$s %5$s every %6$s year" +msgstr "%1$s %2$s puis %3$s le %4$s %5$s chaque %6$s année" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month +#. (e.g. "23rd") +#: includes/wcs-formatting-functions.php:175 +msgid "%1$s %2$s then %3$s on %4$s %5$s each year" +msgstr "%1$s %2$s puis %3$s le %4$s %5$s chaque année" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g. +#. "3rd") +#: includes/wcs-formatting-functions.php:157 +msgid "%1$s %2$s then %3$s on the %4$s day of every %5$s month" +msgstr "%1$s %2$s puis %3$s le %4$s jour de chaque %5$s mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:154 +msgid "%1$s %2$s then %3$s on the last day of every %4$s month" +msgstr "%1$s %2$s puis %3$s le dernier jour de chaque %4$s mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up +#. front then $40 on the 23rd of each month") +#: includes/wcs-formatting-functions.php:138 +msgid "%1$s %2$s then %3$s on the %4$s of each month" +msgstr "%1$s %2$s puis %3$s le %4$s de chaque mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount; (e.g. "$10 up front then $30 on the last day of each +#. month") +#: includes/wcs-formatting-functions.php:135 +msgid "%1$s %2$s then %3$s on the last day of each month" +msgstr "%1$s %2$s puis %3$s le dernier jour de chaque mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front" ), +#. 3$: recurring amount, 4$: interval (e.g. "2nd week"), 5$: day of the week +#. (e.g. "Thursday"); (e.g. "$10 up front, then $20 every 2nd week on +#. Wednesday") +#: includes/wcs-formatting-functions.php:122 +msgid "%1$s %2$s then %3$s every %4$s on %5$s" +msgstr "%1$s %2$s puis %3$s chaque %4$s le %5$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount string, 4$: payment day of the week (e.g. "$15 up +#. front, then $10 every Wednesday") +#: includes/wcs-formatting-functions.php:113 +msgid "%1$s %2$s then %3$s every %4$s" +msgstr "%1$s %2$s puis %3$s chaque %4$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount string (e.g. "£10 / month" ) +#: includes/wcs-formatting-functions.php:99 +msgid "%1$s %2$s then %3$s" +msgstr "%1$s %2$s puis %3$s" + +#: includes/wcs-formatting-functions.php:41 +msgctxt "initial payment on a subscription" +msgid "up front" +msgstr "à l’avance" + +#. translators: placeholder is either subscription key or a subscription id, +#. or, failing that, empty (e.g. "145_21" or "145") +#: includes/wcs-deprecated-functions.php:180 +msgid "" +"Could not get subscription. Most likely the subscription key does not refer " +"to a subscription. The key was: \"%s\"." +msgstr "" +"Impossible d’obtenir l’abonnement. Très probablement, la clé d’abonnement ne " +"fait pas référence à un abonnement. La clé était : « %s »." + +#. translators: placeholder is a date +#: includes/wcs-cart-functions.php:389 +#: tests/unit/wcs_test_wcs_cart_functions.php:225 +msgid "First renewal: %s" +msgstr "Premier renouvellement : %s" + +#: includes/wcs-cart-functions.php:282 +msgid "Free shipping coupon" +msgstr "Code promo livraison gratuite" + +#: includes/wcs-cart-functions.php:227 +msgctxt "shipping method price" +msgid "Free" +msgstr "Gratuit" + +#: includes/upgrades/templates/wcs-upgrade.php:72 +msgid "" +"There was an error with the update. Please refresh the page and try again." +msgstr "" +"Une erreur est survenue lors de la mise à jour. Veuillez rafraîchir la page " +"et réessayer." + +#: includes/upgrades/templates/wcs-upgrade.php:71 +msgid "Update Error" +msgstr "Erreur de mise à jour" + +#. translators: $1: placeholder is number of weeks, 2$: path to the file +#: includes/upgrades/templates/wcs-upgrade.php:66 +msgid "" +"To record the progress of the update a new log file was created. This file " +"will be automatically deleted in %1$d weeks. If you would like to delete it " +"sooner, you can find it here: %2$s" +msgstr "" +"Pour enregistrer la progression de la mise à jour, un nouveau fichier " +"journal a été créé. Ce fichier sera supprimé automatiquement dans " +"%1$d semaines. Si vous voulez le supprimer plus tôt, vous pouvez le trouver " +"ici : %2$s" + +#: includes/upgrades/templates/wcs-upgrade.php:63 +msgid "Continue" +msgstr "Continuer" + +#: includes/upgrades/templates/wcs-upgrade.php:62 +msgid "Your database has been updated successfully!" +msgstr "Votre base de données a été mise à jour avec succès !" + +#: includes/upgrades/templates/wcs-upgrade.php:61 +msgid "Update Complete" +msgstr "Mise à jour terminée" + +#: includes/upgrades/templates/wcs-upgrade.php:53 +msgid "" +"Remember, although the update process may take a while, customers and other " +"non-administrative users can browse and purchase from your store without " +"interruption while the update is in progress." +msgstr "" +"Rappelez-vous que, bien que le processus de mise à jour puisse prendre un " +"certain temps, les clients et autres utilisateurs non administratifs peuvent " +"parcourir et acheter dans votre boutique sans interruption pendant que la " +"mise à jour est en cours." + +#: includes/upgrades/templates/wcs-upgrade.php:51 +msgid "" +"Please keep this page open until the update process completes. No need to " +"refresh or restart the process." +msgstr "" +"Veuillez garder cette page ouverte jusqu’à la fin du processus de mise à " +"jour. Pas besoin de rafraîchir ou de redémarrer le processus." + +#: includes/upgrades/templates/wcs-upgrade.php:50 +msgid "" +"This page will display the results of the process as each batch of " +"subscriptions is updated." +msgstr "" +"Cette page affichera les résultats du processus au fur et à mesure que " +"chaque lot d’abonnements est mis à jour." + +#: includes/upgrades/templates/wcs-upgrade.php:49 +msgid "Update in Progress" +msgstr "Mise à jour en cours" + +#: includes/upgrades/templates/wcs-upgrade.php:45 +msgctxt "text on submit button" +msgid "Update Database" +msgstr "Mettre à jour la base de données" + +#: includes/upgrades/templates/wcs-upgrade.php:43 +msgid "" +"Customers and other non-administrative users can browse and purchase from " +"your store without interruption while the update is in progress." +msgstr "" +"Les clients et autres utilisateurs non administratifs peuvent parcourir et " +"acheter dans votre boutique sans interruption pendant que la mise à jour est " +"en cours." + +#: includes/upgrades/templates/wcs-upgrade.php:41 +msgid "The update process may take a little while, so please be patient." +msgstr "" +"Le processus de mise à jour peut prendre un peu de temps, alors soyez " +"patient." + +#. translators: 1$: number of subscriptions on site, 2$, lower estimate +#. (minutes), 3$: upper estimate +#: includes/upgrades/templates/wcs-upgrade.php:38 +msgid "" +"The full update process for the %1$d subscriptions on your site will take " +"between %2$d and %3$d minutes." +msgstr "" +"Le processus complet de mise à jour des %1$d abonnements sur votre site " +"prendra entre %2$d et %3$d minutes. " + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-upgrade.php:33 +msgid "" +"Before we send you on your way, we need to update your database to the " +"newest version. If you do not have a recent backup of your site, %snow is " +"the time to create one%s." +msgstr "" +"Avant de vous laisser, nous devons mettre à jour votre base de données avec " +"la dernière version. Si vous ne disposez pas d’une sauvegarde récente de " +"votre site, %sil est maintenant temps d’en créer une%s." + +#: includes/upgrades/templates/wcs-upgrade.php:30 +msgid "The WooCommerce Subscriptions plugin has been updated!" +msgstr "L’extension WooCommerce Subscriptions a été mise à jour !" + +#: includes/upgrades/templates/wcs-upgrade.php:29 +msgid "Database Update Required" +msgstr "Mise à jour de base de données obligatoire" + +#: includes/upgrades/templates/wcs-upgrade.php:19 +msgid "WooCommerce Subscriptions Update" +msgstr "Mise à jour de WooCommerce Subscriptions" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:36 +msgid "" +"Rest assured, although the update process may take a little while, it is " +"coded to prevent defects, your site is safe and will be up and running again," +" faster than ever, shortly." +msgstr "" +"Rassurez-vous, bien que le processus de mise à jour puisse prendre un peu de " +"temps, il est codé pour éviter les défauts, votre site est sûr et sera à " +"nouveau opérationnel, plus rapidement que jamais, sous peu." + +#. translators: placeholder is number of seconds +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:34 +msgid "" +"If you received a server error and reloaded the page to find this notice, " +"please refresh the page in %s seconds and the upgrade routine will " +"recommence without issues." +msgstr "" +"Si vous avez reçu une erreur de serveur et que vous voyez cet avis après " +"avoir rechargé la page, veuillez rafraîchir la page dans %s secondes et la " +"routine de mise à niveau recommencera sans problème." + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:31 +msgid "" +"The WooCommerce Subscriptions plugin is currently running its database " +"upgrade routine." +msgstr "" +"L’extension WooCommerce Subscriptions exécute actuellement sa routine de " +"mise à niveau de la base de données." + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:30 +msgid "The Upgrade is in Progress" +msgstr "La mise à niveau est en cours" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:24 +msgid "WooCommerce Subscriptions Update in Progress" +msgstr "Mise à jour de WooCommerce Subscriptions en cours" + +#: includes/upgrades/templates/wcs-about-2-0.php:194 +msgid "Go to WooCommerce Subscriptions Settings" +msgstr "Accéder aux paramètres de WooCommerce Subscriptions" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about-2-0.php:188 +msgid "" +"Want to list all the subscriptions on a site? Get %sexample.com/wc-" +"api/v2/subscriptions/%s. Want the details of a specific subscription? Get " +"%s/wc-api/v2/subscriptions//%s." +msgstr "" +"Vous voulez répertorier tous les abonnements sur un site ? Obtenez %sexample." +"com/wc-api/v2/subscriptions/%s. Vous voulez les détails d’un abonnement " +"spécifique ? Obtenez %s/wc-api/v2/subscriptions//%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:185 +msgid "" +"We didn't just improve interfaces for humans, we also improved them for " +"computers. Your applications can now create, read, update or delete " +"subscriptions via RESTful API endpoints." +msgstr "" +"Nous n’avons pas seulement amélioré les interfaces pour les humains, nous " +"les avons également améliorées pour les ordinateurs. Vos applications " +"peuvent désormais créer, lire, mettre à jour ou supprimer des abonnements " +"via des points de terminaison API RESTful." + +#: includes/upgrades/templates/wcs-about-2-0.php:184 +msgid "REST API Endpoints" +msgstr "Points de terminaison API REST" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about-2-0.php:180 +msgid "" +"Because the %sWC_Subscription%s class extends %sWC_Order%s, you can use its " +"familiar methods, like %s$subscription->update_status()%s or %s$subscription-" +">get_total()%s." +msgstr "" +"Comme la classe %sWC_Subscription%s inclut %sWC_Order%s, vous pouvez " +"utiliser ses méthodes familières, comme %s$subscription->update_status()%s " +"ou %s$subscription->get_total()%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:177 +msgid "" +"Subscriptions 2.0 introduces a new object for working with a subscription at " +"the application level. The cumbersome APIs for retrieving or modifying a " +"subscription's data are gone!" +msgstr "" +"Subscriptions 2.0 introduit un nouvel objet pour fonctionner avec un " +"abonnement au niveau de l’application. Les API encombrantes pour récupérer " +"ou modifier les données d’un abonnement ont disparu !" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:175 +msgid "New %sWC_Subscription%s Object" +msgstr "Nouvel objet %sWC_Subscription%s" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:169 +msgid "" +"Developers can also now use all the familiar WordPress functions, like " +"%sget_posts()%s, to query or modify subscription data." +msgstr "" +"De même, les développeurs peuvent désormais utiliser toutes les fonctions " +"WordPress familières, comme %sget_posts()%s, pour interroger ou modifier les " +"données d’abonnement." + +#: includes/upgrades/templates/wcs-about-2-0.php:166 +msgid "" +"By making a subscription a Custom Order Type, a subscription is also now a " +"custom post type. This makes it faster to query subscriptions and it uses a " +"database schema that is as scalable as WordPress posts and pages." +msgstr "" +"En faisant d’un abonnement un type de commande personnalisé, un abonnement " +"devient également un type d’article personnalisé. Cela accélère " +"l’interrogation des abonnements et utilise un schéma de base de données " +"aussi évolutif que les articles et les pages WordPress." + +#. translators: placeholders are opening and closing code tags +#: includes/upgrades/templates/wcs-about-2-0.php:164 +msgid "New %sshop_subscription%s Post Type" +msgstr "Nouveau type d’article %sshop_subscription%s" + +#: includes/upgrades/templates/wcs-about-2-0.php:158 +msgid "" +"Subscriptions 2.0 introduces a new architecture built on the WooCommerce " +"Custom Order Types API." +msgstr "" +"Subscriptions 2.0 introduit une nouvelle architecture basée sur l’API " +"WooCommerce Custom Order Types." + +#: includes/upgrades/templates/wcs-about-2-0.php:157 +#: includes/upgrades/templates/wcs-about.php:151 +msgid "Peek Under the Hood for Developers" +msgstr "Informations détaillées pour les développeurs" + +#: includes/upgrades/templates/wcs-about-2-0.php:150 +msgid "And much more..." +msgstr "Et bien plus encore…" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:137 +msgid "" +"It was already possible to change a subscription's next payment date, but " +"some store managers wanted to provide a customer with an extended free trial " +"or add an extra month to the expiration date. Now you can change all of " +"these dates from the %sEdit Subscription%s screen." +msgstr "" +"Il était déjà possible de modifier la date du prochain paiement d’un " +"abonnement, mais certains gérants de boutique souhaitaient proposer à un " +"client un essai gratuit prolongé ou ajouter un mois supplémentaire à la date " +"d’expiration. Nous pouvez désormais modifier toutes ces dates sur l’écran " +"%sModifier l’abonnement%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:134 +msgid "Change Trial and End Dates" +msgstr "Modifier les dates d’essai et de fin" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:124 +msgid "" +"For a store manager to change a subscription from automatic to manual " +"renewal payments (or manual to automatic) with Subscriptions v1.5, the " +"database needed to be modified directly. Subscriptions now provides a way " +"for payment gateways to allow you to change that from the new %sEdit " +"Subscription%s interface." +msgstr "" +"Pour qu’un gérant de boutique puisse changer un abonnement de paiements de " +"renouvellement automatiques à manuels (ou de manuels à automatiques) avec " +"Subscriptions v1.5, la base de données devait être modifiée directement. " +"Subscriptions permet désormais aux passerelles de paiement de vous autoriser " +"à changer cela dans la nouvelle interface %sModifier l’abonnement%s." + +#. translators: placeholders are for opening and closing link () tags +#. translators: placeholders are opening and closing anchor tags linking to +#. documentation +#: includes/upgrades/templates/wcs-about-2-0.php:115 +#: includes/upgrades/templates/wcs-about-2-0.php:128 +#: includes/upgrades/templates/wcs-about-2-0.php:141 +#: includes/upgrades/templates/wcs-about.php:120 +#: includes/upgrades/templates/wcs-about.php:131 +#: includes/upgrades/templates/wcs-about.php:142 +#: includes/upgrades/templates/wcs-about.php:170 +#: includes/upgrades/templates/wcs-about.php:191 +msgid "%sLearn more »%s" +msgstr "%sEn savoir plus »%s" + +#. translators: placeholders are for opening and closing link () tags +#: includes/upgrades/templates/wcs-about-2-0.php:111 +msgid "" +"By default, adding new files to an existing subscription product will " +"automatically provide active subscribers with access to the new files. " +"However, now you can enable a %snew content dripping setting%s to provide " +"subscribers with access to new files only after the next renewal payment." +msgstr "" +"Par défaut, l’ajout de nouveaux fichiers à un produit d’abonnement existant " +"fournira automatiquement aux abonnés actifs l’accès aux nouveaux fichiers. " +"Cependant, vous pouvez activer un %snouveau paramètre de diffusion de " +"contenu%s pour permettre aux abonnés d’accéder aux nouveaux fichiers " +"uniquement après le prochain paiement de renouvellement." + +#: includes/admin/class-wc-subscriptions-admin.php:1348 +#: includes/upgrades/templates/wcs-about-2-0.php:108 +msgid "Drip Downloadable Content" +msgstr "Diffuser le contenu téléchargeable" + +#. translators: placeholders are opening and closing link tags +#: includes/upgrades/templates/wcs-about-2-0.php:97 +msgid "Learn more about the new %sView Subscription page%s." +msgstr "En savoir plus sur la nouvelle %spage Afficher l’abonnement%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:93 +msgid "" +"This new page is also where the customer can suspend or cancel their " +"subscription, change payment method, change shipping address or " +"upgrade/downgrade an item." +msgstr "" +"Cette nouvelle page permet également au client de suspendre ou d’annuler son " +"abonnement, de modifier le moyen de paiement, de modifier l’adresse de " +"livraison ou de mettre à niveau/rétrograder un article." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:91 +msgid "" +"Your customers can now view the full details of a subscription, including " +"line items, billing and shipping address, billing schedule and renewal " +"orders, from a special %sMy Account > View Subscription%s page." +msgstr "" +"Vos clients peuvent désormais voir tous les détails d’un abonnement, " +"notamment les articles d'une ligne, l’adresse de facturation et de livraison," +" le calendrier de facturation et les commandes de renouvellement, sur une " +"page spéciale %sMon compte > Afficher l’abonnement%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:87 +msgid "New View Subscription Page" +msgstr "Nouvelle page Afficher l’abonnement" + +#. translators: placeholers are link tags: 1$-2$ new subscription page, 3$-4$: +#. docs on woocommerce.com +#: includes/upgrades/templates/wcs-about-2-0.php:76 +msgid "" +"%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new interface." +msgstr "" +"%1$sAjoutez un abonnement%2$s maintenant ou %3$sdécouvrez%4$s la nouvelle " +"interface." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:72 +msgid "" +"The new interface is also built on the existing %sEdit Order%s screen. If " +"you've ever modified an order, you already know how to modify a subscription." +msgstr "" +"La nouvelle interface est également basée sur l’écran %sModifier la " +"commande%s existant. Si vous avez déjà modifié une commande, vous savez déjà " +"comment modifier un abonnement." + +#: includes/upgrades/templates/wcs-about-2-0.php:69 +msgid "" +"Subscriptions v2.0 introduces a new administration interface to add or edit " +"a subscription. You can make all the familiar changes, like modifying " +"recurring totals or subscription status. You can also make some new " +"modifications, like changing the expiration date, adding a shipping cost or " +"adding a product line item." +msgstr "" +"Subscriptions v2.0 introduit une nouvelle interface d’administration pour " +"ajouter ou modifier un abonnement. Vous pouvez apporter toutes les " +"modifications habituelles, comme la modification des totaux récurrents ou de " +"l’état de l’abonnement. Vous pouvez également apporter de nouvelles " +"modifications, comme modifier la date d’expiration, ajouter des frais de " +"port ou ajouter article d'une ligne de produits." + +#: includes/upgrades/templates/wcs-about-2-0.php:68 +msgid "New Add/Edit Subscription Screen" +msgstr "Nouvel écran Ajouter/Modifier un abonnement" + +#. translators: placeholders are opening and closing link tags +#: includes/upgrades/templates/wcs-about-2-0.php:56 +msgid "Learn more about the new %smultiple subscriptions%s feature." +msgstr "" +"En savoir plus sur la nouvelle fonctionnalité %sabonnements multiples%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:53 +msgid "" +"Customers can now purchase different subscription products in one " +"transaction. The products can bill on any schedule and have any combination " +"of sign-up fees and/or free trials." +msgstr "" +"Les clients peuvent désormais acheter différents produits d’abonnement en " +"une seule transaction. Les produits peuvent être facturés selon n’importe " +"quel calendrier et avoir n’importe quelle combinaison de frais d’inscription " +"et/ou d’essais gratuits." + +#: includes/upgrades/templates/wcs-about-2-0.php:52 +msgid "It's now easier for your customers to buy more subscriptions!" +msgstr "" +"Il est désormais plus facile pour vos clients d’acheter plus d’abonnements !" + +#: includes/upgrades/templates/wcs-about-2-0.php:51 +msgid "Multiple Subscriptions" +msgstr "Abonnements multiples" + +#: includes/upgrades/templates/wcs-about-2-0.php:42 +#: includes/upgrades/templates/wcs-about.php:41 +msgid "Check Out What's New" +msgstr "Découvrir les nouveautés" + +#. translators: placeholder is version number +#: includes/upgrades/templates/wcs-about-2-0.php:31 +#: includes/upgrades/templates/wcs-about.php:30 +msgid "Version %s" +msgstr "Version %s" + +#: includes/upgrades/templates/update-welcome-notice.php:6 +#: includes/upgrades/templates/wcs-about-2-0.php:25 +#: includes/upgrades/templates/wcs-about.php:24 +msgid "We hope you enjoy it!" +msgstr "Nous espérons que vous l’apprécierez !" + +#: includes/upgrades/templates/wcs-about-2-0.php:24 +msgid "" +"Version 2.0 has been in development for more than a year. We've reinvented " +"the extension to take into account 3 years of feedback from store managers." +msgstr "" +"La version 2.0 est en développement depuis plus d’un an. Nous avons " +"réinventé l’extension pour prendre en compte 3 ans de commentaires de la " +"part des gérants de boutique." + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/templates/update-welcome-notice.php:2 +#: includes/upgrades/templates/wcs-about-2-0.php:23 +#: includes/upgrades/templates/wcs-about.php:22 +msgid "" +"Thank you for updating to the latest version of WooCommerce Subscriptions." +msgstr "Merci d’être passé à la dernière version de WooCommerce Subscriptions." + +#: includes/upgrades/templates/wcs-about-2-0.php:20 +msgid "Welcome to Subscriptions 2.0" +msgstr "Bienvenue dans Subscriptions 2.0" + +#: includes/upgrades/class-wc-subscriptions-upgrader.php:640 +msgid "About WooCommerce Subscriptions" +msgstr "À propos de WooCommerce Subscriptions" + +#: includes/upgrades/class-wc-subscriptions-upgrader.php:640 +msgid "Welcome to WooCommerce Subscriptions 2.1" +msgstr "Bienvenue dans WooCommerce Subscriptions 2.1" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, +#. 4$: break tag +#: includes/upgrades/class-wc-subscriptions-upgrader.php:389 +msgid "" +"Unable to upgrade subscriptions.%4$sError: %1$s%4$sPlease refresh the page " +"and try again. If problem persists, %2$scontact support%3$s." +msgstr "" +"Impossible de mettre à niveau les abonnements.%4$sErreur : %1$s%4$sVeuillez " +"rafraîchir la page et réessayer. Si le problème persiste, %2$scontactez " +"l’assistance%3$s." + +#. translators: placeholder is number of upgraded subscriptions +#: includes/upgrades/class-wc-subscriptions-upgrader.php:355 +msgctxt "used in the subscriptions upgrader" +msgid "Marked %s subscription products as \"sold individually\"." +msgstr "%s produits d’abonnement marqués comme « vendus individuellement »." + +#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 & +#. 1.5") +#: includes/upgrades/class-wc-subscriptions-upgrader.php:347 +msgid "Database updated to version %s" +msgstr "Base de données mise à jour vers la version %s" + +#: includes/payment-retry/class-wcs-retry-post-store.php:47 +msgid "No retries found in trash" +msgstr "Aucune nouvelle tentative trouvée dans la corbeille" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:138 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:229 +#: includes/payment-retry/class-wcs-retry-post-store.php:40 +msgid "Edit" +msgstr "Modifier" + +#: includes/payment-retry/class-wcs-retry-post-store.php:38 +msgid "Add" +msgstr "Ajouter" + +#. translators: placeholder is a number of days. +#: includes/wcs-time-functions.php:58 +msgid "%s day" +msgid_plural "a %s-day" +msgstr[0] "%s jour" +msgstr[1] "de %s jours" + +#. translators: placeholder is a number of weeks. +#: includes/wcs-time-functions.php:60 +msgid "%s week" +msgid_plural "a %s-week" +msgstr[0] "%s semaine" +msgstr[1] "de %s semaines" + +#. translators: placeholder is a number of months. +#: includes/wcs-time-functions.php:62 +msgid "%s month" +msgid_plural "a %s-month" +msgstr[0] "%s mois" +msgstr[1] "de %s mois" + +#. translators: placeholder is a number of years. +#: includes/wcs-time-functions.php:64 +msgid "%s year" +msgid_plural "a %s-year" +msgstr[0] "%s an" +msgstr[1] "de %s ans" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:66 +msgid "Subscription reactivated with PayPal" +msgstr "Abonnement réactivé avec PayPal" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:53 +msgid "Subscription suspended with PayPal" +msgstr "Abonnement suspendu avec PayPal" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42 +msgid "Subscription cancelled with PayPal" +msgstr "Abonnement annulé avec PayPal" + +#. translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma +#. separated +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:78 +msgctxt "item name sent to paypal" +msgid "Subscription %1$s (Order %2$s) - %3$s" +msgstr "Abonnement %1$s (Commande %2$s) - %3$s" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:503 +msgid "IPN subscription payment failure." +msgstr "Échec du paiement d’abonnement IPN." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:487 +msgid "IPN subscription cancelled." +msgstr "Abonnement IPN annulé." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:464 +msgid "IPN subscription suspended." +msgstr "Abonnement IPN suspendu." + +#. translators: placeholder is payment status (e.g. "completed") +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:422 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:431 +msgctxt "used in order note" +msgid "IPN subscription payment %s." +msgstr "Paiement d’abonnement IPN %s." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:374 +msgid "IPN subscription failing payment method changed." +msgstr "Abonnement IPN échouant au moyen de paiement modifié." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:332 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:412 +msgid "IPN subscription payment completed." +msgstr "Paiement d’abonnement IPN terminé." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:279 +msgid "IPN subscription sign up completed." +msgstr "Inscription d’abonnement IPN terminée." + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php:94 +msgid "Billing agreement cancelled at PayPal." +msgstr "Accord de facturation annulé chez PayPal." + +#: includes/privacy/class-wcs-privacy.php:236 +msgid "N/A" +msgstr "ND" + +#. translators: placeholder is localised datetime +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119 +msgid "expected clearing date %s" +msgstr "date de compensation prévue %s" + +#. translators: %s: product SKU. +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:536 +msgid "SKU: %s" +msgstr "UGS : %s" + +#. translators: 1$: new status (e.g. "Cancel"), 2$: blog name +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:416 +msgctxt "data sent to paypal" +msgid "%1$s subscription event triggered at %2$s" +msgstr "%1$s événement d’abonnement déclenché sur %2$s" + +#. translators: placeholder is blogname +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:306 +msgid "%s - Order" +msgstr "%s - Commande" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:279 +msgid "Total Discount" +msgstr "Remise totale" + +#. translators: placeholder is blogname +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:71 +msgctxt "data sent to paypal" +msgid "Orders with %s" +msgstr "Commandes avec %s" + +#. translators: placeholders are opening and closing link tags. 1$-2$: docs on +#. woocommerce, 3$-4$: dismiss link +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:172 +msgid "" +"There is a problem with PayPal. Your PayPal account is issuing out-of-date " +"subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." +msgstr "" +"Il y a un problème avec PayPal. Votre compte PayPal émet des ID d’abonnement " +"obsolètes. %1$sEn savoir plus%2$s. %3$sIgnorer%4$s." + +#. translators: placeholders are link opening and closing tags. 1$-2$: to +#. gateway settings, 3$-4$: support docs on woocommerce.com +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:159 +msgid "" +"There is a problem with PayPal. Your API credentials may be incorrect. " +"Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s." +msgstr "" +"Il y a un problème avec PayPal. Vos identifiants de connexion API peuvent " +"être incorrects. Veuillez mettre à jour vos %1$sidentifiants de connexion " +"API%2$s. %3$sEn savoir plus%4$s." + +#. translators: placeholders are opening and closing strong tags. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:148 +msgid "" +"%1$sPayPal Reference Transactions are enabled on your account%2$s. All " +"subscription management features are now enabled. Happy selling!" +msgstr "" +"%1$sPayPal Reference Transactions est activé sur votre compte%2$s. Toutes " +"les fonctionnalités de gestion des abonnements sont maintenant activées. " +"Bonne vente !" + +#. translators: opening/closing tags - links to documentation. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122 +msgid "" +"%1$sPayPal Reference Transactions are not enabled on your account%2$s, some " +"subscription management features are not enabled. Please contact PayPal and " +"request they %3$senable PayPal Reference Transactions%4$s on your account. " +"%5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" +"%1$sPayPal Reference Transactions n’est pas activé sur votre compte%2$s, " +"certaines fonctionnalités de gestion des abonnements ne sont pas activées. " +"Veuillez contacter PayPal et leur demander d’%3$sactiver PayPal Reference " +"Transactions%4$s sur votre compte. %5$sVérifier le compte PayPal%6$s %3$sEn " +"savoir plus%7$s" + +#. translators: placeholders are opening and closing link tags. 1$-2$: to docs +#. on woocommerce, 3$-4$ to gateway settings on the site +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:110 +msgid "" +"PayPal is inactive for subscription transactions. Please %1$sset up the " +"PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for " +"Subscriptions." +msgstr "" +"PayPal est inactif pour les transactions d’abonnement. Veuillez " +"%1$sconfigurer l’IPN PayPal%2$s et %3$ssaisir vos identifiants de connexion " +"API%4$s afin d’activer PayPal pour Subscriptions." + +#. translators: $1 and $2 are opening and closing strong tags, respectively. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:63 +msgid "" +"It is %1$sstrongly recommended you do not change the Receiver Email " +"address%2$s if you have active subscriptions with PayPal. Doing so can break " +"existing subscriptions." +msgstr "" +"Il vous est %1$sfortement recommandé de ne pas modifier l’adresse e-mail du " +"destinataire%2$s si vous avez des abonnements actifs avec PayPal. Cela peut " +"interrompre les abonnements existants." + +#: includes/gateways/paypal/class-wcs-paypal.php:460 +msgid "" +"Are you sure you want to change the payment method from PayPal standard?\n" +"\n" +"This will suspend the subscription at PayPal." +msgstr "" +"Voulez-vous vraiment modifier le moyen de paiement de PayPal Standard ?\n" +"\n" +"Cela suspendra l’abonnement chez PayPal." + +#. translators: placeholder is a transaction ID. +#: includes/gateways/paypal/class-wcs-paypal.php:407 +msgid "PayPal payment approved (ID: %s)" +msgstr "Paiement PayPal approuvé (ID : %s)" + +#. translators: placeholder is PayPal transaction status message +#: includes/gateways/paypal/class-wcs-paypal.php:403 +msgid "PayPal payment declined: %s" +msgstr "Paiement PayPal refusé : %s" + +#. translators: placeholder is PayPal transaction status message +#: includes/gateways/paypal/class-wcs-paypal.php:391 +msgid "PayPal Transaction Held: %s" +msgstr "Transaction PayPal en cours : %s" + +#. translators: placeholders are PayPal API error code and PayPal API error +#. message +#: includes/gateways/paypal/class-wcs-paypal.php:386 +msgid "PayPal API error: (%1$d) %2$s" +msgstr "Erreur d’API PayPal : (%1$d) %2$s" + +#: includes/gateways/paypal/class-wcs-paypal.php:282 +msgid "" +"An error occurred, please try again or try an alternate form of payment." +msgstr "" +"Une erreur est survenue, veuillez réessayer ou essayer un autre mode de " +"paiement." + +#: includes/gateways/paypal/class-wcs-paypal.php:220 +msgid "Unable to find order for PayPal billing agreement." +msgstr "Commande pour l’accord de facturation PayPal introuvable." + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:137 +msgid "" +"Sorry, it seems there are no available payment methods which support " +"subscriptions. Please contact us if you require assistance or wish to make " +"alternate arrangements." +msgstr "" +"Désolé, il semble qu’aucun moyen de paiement ne soit disponible pour les " +"abonnements. Veuillez nous contacter si vous avez besoin d’aide ou si vous " +"désirez mettre en place une alternative." + +#: includes/emails/class-wcs-email-new-switch-order.php:26 +msgid "[{blogname}] Subscription Switched ({order_number}) - {order_date}" +msgstr "[{blogname}] Abonnement changé ({order_number}) - {order_date}" + +#: includes/emails/class-wcs-email-new-switch-order.php:23 +msgid "" +"Subscription switched emails are sent when a customer switches a " +"subscription." +msgstr "" +"Les e-mails de changement d’abonnement sont envoyés lorsqu’un client change " +"d’abonnement." + +#: includes/emails/class-wcs-email-new-switch-order.php:22 +#: includes/emails/class-wcs-email-new-switch-order.php:25 +msgid "Subscription Switched" +msgstr "Abonnement changé" + +#: includes/emails/class-wcs-email-new-renewal-order.php:26 +msgid "" +"[{blogname}] New subscription renewal order ({order_number}) - {order_date}" +msgstr "" +"[{blogname}] Nouvelle commande de renouvellement d’abonnement ({order_number}" +") - {order_date}" + +#: includes/emails/class-wcs-email-new-renewal-order.php:25 +msgid "New subscription renewal order" +msgstr "Nouvelle commande de renouvellement d’abonnement" + +#: includes/emails/class-wcs-email-new-renewal-order.php:23 +msgid "" +"New renewal order emails are sent when a subscription renewal payment is " +"processed." +msgstr "" +"Les e-mails de nouvelle commande de renouvellement sont envoyés lorsqu’un " +"paiement de renouvellement d’abonnement est traité." + +#: includes/emails/class-wcs-email-new-renewal-order.php:22 +msgid "New Renewal Order" +msgstr "Nouvelle commande de renouvellement" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:49 +msgid "Invoice for renewal order {order_number}" +msgstr "Facture pour la commande de renouvellement {order_number}" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:48 +msgid "Invoice for renewal order {order_number} from {order_date}" +msgstr "" +"Facture pour la commande de renouvellement {order_number} du {order_date}" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:40 +msgid "Customer Renewal Invoice" +msgstr "Facture de renouvellement client" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:29 +msgid "Your {blogname} renewal order receipt from {order_date}" +msgstr "Votre reçu de commande de renouvellement de {blogname} du {order_date}" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:28 +msgid "Thank you for your order" +msgstr "Merci pour votre commande" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:25 +msgid "" +"This is an order notification sent to the customer after payment for a " +"subscription renewal order is completed. It contains the renewal order " +"details." +msgstr "" +"Il s’agit d’une notification de commande envoyée au client après le paiement " +"d’une commande de renouvellement d’abonnement. Elle contient les détails de " +"la commande de renouvellement." + +#: includes/emails/class-wcs-email-processing-renewal-order.php:24 +msgid "Processing Renewal order" +msgstr "Traitement de la commande de renouvellement" + +#: includes/emails/class-wcs-email-completed-switch-order.php:39 +msgid "" +"Your {blogname} subscription change from {order_date} is complete - download " +"your files" +msgstr "" +"Votre changement d’abonnement de {blogname} du {order_date} est terminé, " +"téléchargez vos fichiers" + +#: includes/emails/class-wcs-email-completed-switch-order.php:38 +msgid "Your subscription change is complete - download your files" +msgstr "Votre changement d’abonnement est terminé, téléchargez vos fichiers" + +#: includes/emails/class-wcs-email-completed-switch-order.php:31 +msgid "Your {blogname} subscription change from {order_date} is complete" +msgstr "" +"Votre changement d’abonnement de {blogname} du {order_date} est terminé" + +#: includes/emails/class-wcs-email-completed-switch-order.php:30 +msgid "Your subscription change is complete" +msgstr "Votre changement d’abonnement est terminé" + +#: includes/emails/class-wcs-email-completed-switch-order.php:27 +msgid "" +"Subscription switch complete emails are sent to the customer when a " +"subscription is switched successfully." +msgstr "" +"Les e-mails de changement d’abonnement terminé sont envoyés au client " +"lorsqu’un abonnement est changé avec succès." + +#: includes/emails/class-wcs-email-completed-switch-order.php:26 +msgid "Subscription Switch Complete" +msgstr "Changement d’abonnement terminé" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:26 +msgid "" +"Renewal order complete emails are sent to the customer when a subscription " +"renewal order is marked complete and usually indicates that the item for " +"that renewal period has been shipped." +msgstr "" +"Des e-mails de fin de commande de renouvellement sont envoyés au client " +"lorsqu’une commande de renouvellement d’abonnement est marquée comme " +"terminée. Ils indiquent en général que l’article pour cette période de " +"renouvellement a été expédié." + +#: includes/emails/class-wcs-email-completed-renewal-order.php:25 +msgid "Completed Renewal Order" +msgstr "Commande de renouvellement terminée" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:181 +#: includes/emails/class-wcs-email-expired-subscription.php:179 +#: includes/emails/class-wcs-email-on-hold-subscription.php:179 +msgctxt "email type" +msgid "Multipart" +msgstr "Multi-parties" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:180 +#: includes/emails/class-wcs-email-expired-subscription.php:178 +#: includes/emails/class-wcs-email-on-hold-subscription.php:178 +msgctxt "email type" +msgid "HTML" +msgstr "HTML" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:179 +#: includes/emails/class-wcs-email-expired-subscription.php:177 +#: includes/emails/class-wcs-email-on-hold-subscription.php:177 +msgctxt "email type" +msgid "Plain text" +msgstr "Texte brut" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:175 +#: includes/emails/class-wcs-email-expired-subscription.php:173 +#: includes/emails/class-wcs-email-on-hold-subscription.php:173 +msgid "Choose which format of email to send." +msgstr "Choisissez le format d’envoi des e-mails." + +#. translators: %s: default e-mail heading. +#: includes/emails/class-wcs-email-expired-subscription.php:166 +#: includes/emails/class-wcs-email-on-hold-subscription.php:166 +msgid "" +"This controls the main heading contained within the email notification. " +"Leave blank to use the default heading: %s." +msgstr "" +"Cela contrôle l’en-tête principal contenu dans la notification par e-mail. " +"Laisser vide pour utiliser l’en-tête par défaut : %s." + +#. translators: %s: default e-mail subject. +#: includes/emails/class-wcs-email-cancelled-subscription.php:160 +#: includes/emails/class-wcs-email-expired-subscription.php:158 +#: includes/emails/class-wcs-email-on-hold-subscription.php:158 +msgid "" +"This controls the email subject line. Leave blank to use the default subject:" +" %s." +msgstr "" +"Cela contrôle la ligne d’objet de l’e-mail. Laisser vide pour utiliser le " +"sujet par défaut : %s." + +#: includes/emails/class-wcs-email-cancelled-subscription.php:157 +#: includes/emails/class-wcs-email-expired-subscription.php:155 +#: includes/emails/class-wcs-email-on-hold-subscription.php:155 +msgctxt "of an email" +msgid "Subject" +msgstr "Sujet" + +#. translators: placeholder is admin email +#: includes/emails/class-wcs-email-cancelled-subscription.php:152 +#: includes/emails/class-wcs-email-expired-subscription.php:150 +#: includes/emails/class-wcs-email-on-hold-subscription.php:150 +msgid "Enter recipients (comma separated) for this email. Defaults to %s." +msgstr "" +"Saisir les destinataires (séparés par une virgule) pour cet e-mail. Par " +"défaut à %s." + +#: includes/emails/class-wcs-email-cancelled-subscription.php:149 +#: includes/emails/class-wcs-email-expired-subscription.php:147 +#: includes/emails/class-wcs-email-on-hold-subscription.php:147 +msgctxt "of an email" +msgid "Recipient(s)" +msgstr "Destinataire(s)" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:145 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:212 +#: includes/emails/class-wcs-email-expired-subscription.php:143 +#: includes/emails/class-wcs-email-on-hold-subscription.php:143 +msgid "Enable this email notification" +msgstr "Activer cette notification par e-mail" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:143 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:210 +#: includes/emails/class-wcs-email-expired-subscription.php:141 +#: includes/emails/class-wcs-email-on-hold-subscription.php:141 +msgctxt "an email notification" +msgid "Enable/Disable" +msgstr "Activer/Désactiver" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:29 +msgid "Subscription Cancelled" +msgstr "Abonnement annulé" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:27 +msgid "" +"Cancelled Subscription emails are sent when a customer's subscription is " +"cancelled (either by a store manager, or the customer)." +msgstr "" +"Les e-mails d’abonnement annulé sont envoyés lorsque l’abonnement d’un " +"client est annulé (par un gérant de boutique ou par le client)." + +#: includes/emails/class-wcs-email-cancelled-subscription.php:26 +msgid "Cancelled Subscription" +msgstr "Abonnement annulé" + +#: includes/class-wcs-webhooks.php:112 +msgid " Subscription deleted" +msgstr "Abonnement supprimé" + +#: includes/class-wcs-webhooks.php:111 +msgid " Subscription updated" +msgstr "Abonnement mis à jour" + +#: includes/class-wcs-webhooks.php:110 +msgid " Subscription created" +msgstr "Abonnement créé" + +#. translators: placeholder is subscription's new status, translated +#: includes/class-wcs-user-change-status-handler.php:116 +msgid "" +"That subscription can not be changed to %s. Please contact us if you need " +"assistance." +msgstr "" +"Cet abonnement ne peut pas être modifié sur %s. Contactez-nous si vous avez " +"besoin d’aide." + +#: includes/class-wcs-user-change-status-handler.php:103 +msgid "" +"That subscription does not exist. Please contact us if you need assistance." +msgstr "" +"Cet abonnement n’existe pas. Contactez-nous si vous avez besoin d’aide." + +#: includes/class-wcs-user-change-status-handler.php:71 +msgid "" +"You can not suspend that subscription - the suspension limit has been " +"reached. Please contact us if you need assistance." +msgstr "" +"Vous ne pouvez pas suspendre cet abonnement - la limite de suspension a été " +"atteinte. Contactez-nous si vous avez besoin d’aide." + +#: includes/class-wcs-user-change-status-handler.php:61 +msgid "" +"You can not reactivate that subscription until paying to renew it. Please " +"contact us if you need assistance." +msgstr "" +"Vous ne pouvez pas réactiver cet abonnement tant que vous n’avez pas payé " +"pour le renouveler. Contactez-nous si vous avez besoin d’aide." + +#: includes/class-wcs-remove-item.php:188 +msgid "" +"The item was not removed because this Subscription's payment method does not " +"support removing an item." +msgstr "" +"L’article n’a pas été supprimé, car le moyen de paiement de cet abonnement " +"ne prend pas en charge la suppression d’un article." + +#: includes/class-wcs-remove-item.php:184 +msgid "You cannot remove an item that does not exist. " +msgstr "Vous ne pouvez pas supprimer un article qui n’existe pas. " + +#: includes/class-wcs-remove-item.php:180 +msgid "You cannot modify a subscription that does not belong to you." +msgstr "Vous ne pouvez pas modifier un abonnement qui ne vous appartient pas." + +#: includes/class-wcs-remove-item.php:176 +#: includes/class-wcs-user-change-status-handler.php:107 +msgid "Security error. Please contact us if you need assistance." +msgstr "Erreur de sécurité. Contactez-nous si vous avez besoin d’aide." + +#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: +#. closing link tags +#: includes/class-wcs-remove-item.php:140 +msgid "" +"You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" +msgstr "" +"Vous avez bien supprimé « %1$s » de votre abonnement. %2$sAnnuler ?%3$s" + +#. translators: 1$: product name, 2$: product id +#: includes/class-wcs-remove-item.php:137 +msgctxt "used in order note" +msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" +"Le client a supprimé « %1$s » (ID produit : n°%2$d) sur la page Mon compte." + +#: includes/class-wcs-remove-item.php:119 +msgid "Your request to undo your previous action was unsuccessful." +msgstr "Votre demande d’annulation de votre action précédente a échoué." + +#. translators: 1$: product name, 2$: product id +#: includes/class-wcs-remove-item.php:114 +msgctxt "used in order note" +msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" +"Le client a ajouté « %1$s » (ID produit : n°%2$d) sur la page Mon compte." + +#. translators: %d: subscription ID. +#: includes/class-wcs-remove-item.php:79 +msgctxt "hash before subscription ID" +msgid "Subscription #%d does not exist." +msgstr "L’abonnement n°%d n’existe pas." + +#. translators: %s: subscription ID. +#. translators: %s: order number. +#. translators: placeholder is a subscription ID. +#: includes/class-wc-subscriptions-addresses.php:207 +#: includes/class-wc-subscriptions-change-payment-gateway.php:741 +#: includes/class-wcs-query.php:101 +msgctxt "hash before order number" +msgid "Subscription #%s" +msgstr "Abonnement n°%s" + +#: includes/class-wcs-change-payment-method-admin.php:122 +msgid "Please choose a valid payment gateway to change to." +msgstr "" +"Veuillez choisir une passerelle de paiement valide vers laquelle passer." + +#: includes/class-wcs-cart-resubscribe.php:91 +#: includes/class-wcs-cart-resubscribe.php:119 +msgid "Complete checkout to resubscribe." +msgstr "Terminez la validation de commande pour vous réabonner." + +#: includes/class-wcs-cart-resubscribe.php:82 +msgid "" +"You can not resubscribe to that subscription. Please contact us if you need " +"assistance." +msgstr "" +"Vous ne pouvez pas vous réabonner à cet abonnement. Contactez-nous si vous " +"avez besoin d’aide." + +#: includes/class-wcs-cart-resubscribe.php:74 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:91 +msgid "That subscription does not exist. Has it been deleted?" +msgstr "Cet abonnement n’existe pas. A-t-il été supprimé ?" + +#: includes/class-wcs-cart-resubscribe.php:70 +msgid "There was an error with your request to resubscribe. Please try again." +msgstr "" +"Une erreur est survenue lors de votre demande de réabonnement. Veuillez " +"réessayer." + +#: includes/class-wcs-cart-renewal.php:647 +msgid "All linked subscription items have been removed from the cart." +msgstr "Tous les articles d’abonnement liés ont été supprimés du panier." + +#: includes/class-wcs-cart-renewal.php:376 +msgid "" +"We couldn't find the original renewal order for an item in your cart. The " +"item was removed." +msgid_plural "" +"We couldn't find the original renewal orders for items in your cart. The " +"items were removed." +msgstr[0] "" +"Nous n’avons pas trouvé la commande de renouvellement d’origine pour un " +"article dans votre panier. L’article a été supprimé." +msgstr[1] "" +"Nous n’avons pas trouvé les commandes de renouvellement d’origine pour des " +"articles dans votre panier. Les articles ont été supprimés." + +#: includes/class-wcs-cart-renewal.php:369 +msgid "" +"We couldn't find the original subscription for an item in your cart. The " +"item was removed." +msgid_plural "" +"We couldn't find the original subscriptions for items in your cart. The " +"items were removed." +msgstr[0] "" +"Nous n’avons pas trouvé l’abonnement d’origine pour un article dans votre " +"panier. L’article a été supprimé." +msgstr[1] "" +"Nous n’avons pas trouvé les abonnements d’origine pour des articles dans " +"votre panier. Les articles ont été supprimés." + +#. translators: %s is subscription's number +#: includes/class-wcs-cart-renewal.php:327 +msgid "Subscription #%s has not been added to the cart." +msgstr "L’abonnement n°%s n’a pas été ajouté au panier." + +#. translators: placeholder is an item name +#: includes/class-wcs-cart-renewal.php:292 +msgid "" +"The %s product has been deleted and can no longer be renewed. Please choose " +"a new product or contact us for assistance." +msgstr "" +"Le produit %s a été supprimé et ne peut plus être renouvelé. Veuillez " +"choisir un nouveau produit ou nous contacter pour obtenir de l’aide." + +#: includes/class-wcs-cart-initial-payment.php:62 +#: includes/class-wcs-cart-renewal.php:194 +msgid "That doesn't appear to be your order." +msgstr "Cela ne semble pas être votre commande." + +#: includes/class-wcs-auth.php:45 +msgid "View and manage subscriptions" +msgstr "Afficher et gérer les abonnements" + +#: includes/class-wcs-auth.php:42 +msgid "Create subscriptions" +msgstr "Créer des abonnements" + +#: includes/class-wcs-auth.php:39 +msgid "View subscriptions" +msgstr "Afficher les abonnements" + +#. translators: placeholder is a date +#: includes/class-wc-subscriptions-synchroniser.php:841 +msgid "First payment: %s" +msgstr "Premier paiement : %s" + +#. translators: placeholder is a date +#: includes/class-wc-subscriptions-synchroniser.php:838 +msgid "First payment prorated. Next payment: %s" +msgstr "Premier paiement au prorata. Paiement suivant : %s" + +#: includes/class-wc-subscriptions-synchroniser.php:831 +msgid "Today!" +msgstr "Aujourd’hui !" + +#: includes/class-wc-subscriptions-synchroniser.php:783 +msgid "Last day of the month" +msgstr "Dernier jour du mois" + +#. translators: placeholder is a number of day with language specific suffix +#. applied (e.g. "1st", "3rd", "5th", etc...) +#: includes/class-wc-subscriptions-synchroniser.php:781 +msgid "%s day of the month" +msgstr "%s jour du mois" + +#. translators: placeholder is a day of the week +#: includes/class-wc-subscriptions-synchroniser.php:775 +msgid "%s each week" +msgstr "%s chaque semaine" + +#: includes/class-wc-subscriptions-synchroniser.php:750 +#: includes/class-wc-subscriptions-synchroniser.php:767 +msgid "Do not synchronise" +msgstr "Ne pas synchroniser" + +#: includes/class-wc-subscriptions-switcher.php:432 +#: includes/class-wc-subscriptions-synchroniser.php:235 +msgctxt "when to prorate first payment / subscription length" +msgid "For Virtual Subscription Products Only" +msgstr "Pour les produits d’abonnement virtuels uniquement" + +#: includes/class-wc-subscriptions-synchroniser.php:227 +msgid "" +"If a subscription is synchronised to a specific day of the week, month or " +"year, charge a prorated amount for the subscription at the time of sign up." +msgstr "" +"Si un abonnement est synchronisé sur un jour spécifique de la semaine, du " +"mois ou de l’année, facturez un montant au prorata pour l’abonnement au " +"moment de l’inscription." + +#: includes/class-wc-subscriptions-synchroniser.php:219 +msgid "Align Subscription Renewal Day" +msgstr "Aligner le jour de renouvellement d’abonnement" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-synchroniser.php:213 +msgctxt "used in the general subscription options page" +msgid "" +"Align subscription renewal to a specific day of the week, month or year. For " +"example, the first day of the month. %1$sLearn more%2$s." +msgstr "" +"Alignez le renouvellement d’abonnement sur un jour spécifique de la semaine, " +"du mois ou de l’année. Par exemple, le premier jour du mois. %1$sEn savoir " +"plus%2$s." + +#: includes/class-wc-subscriptions-synchroniser.php:210 +msgid "Synchronisation" +msgstr "Synchronisation" + +#. translators: placeholder is a year (e.g. "2016") +#: includes/class-wc-subscriptions-synchroniser.php:51 +msgctxt "used in subscription product edit screen" +msgid "" +"Align the payment date for this subscription to a specific day of the year. " +"If the date has already taken place this year, the first payment will be " +"processed in %s. Set the day to 0 to disable payment syncing for this " +"product." +msgstr "" +"Alignez la date de paiement de cet abonnement sur un jour spécifique de " +"l’année. Si la date a déjà eu lieu cette année, le premier paiement sera " +"traité en %s. Définissez le jour sur 0 pour désactiver la synchronisation " +"des paiements pour ce produit." + +#: includes/class-wc-subscriptions-synchroniser.php:49 +msgid "" +"Align the payment date for all customers who purchase this subscription to a " +"specific day of the week or month." +msgstr "" +"Alignez la date de paiement pour tous les clients qui achètent cet " +"abonnement sur un jour spécifique de la semaine ou du mois." + +#: templates/admin/deprecated/html-variation-synchronisation.php:30 +msgid "Synchronise Renewals" +msgstr "Synchroniser les renouvellements" + +#. translators: %1: product subtotal, %2: HTML span tag, %3: direction +#. (upgrade, downgrade, crossgrade), %4: closing HTML span tag +#: includes/class-wc-subscriptions-switcher.php:1866 +msgctxt "product subtotal string" +msgid "%1$s %2$s(%3$s)%4$s" +msgstr "%1$s %2$s(%3$s)%4$s" + +#: includes/class-wc-subscriptions-switcher.php:1861 +msgctxt "a switch type" +msgid "Crossgrade" +msgstr "Reclassement" + +#: includes/class-wc-subscriptions-switcher.php:1858 +msgctxt "a switch type" +msgid "Upgrade" +msgstr "Mise à niveau" + +#: includes/class-wc-subscriptions-switcher.php:1855 +msgctxt "a switch type" +msgid "Downgrade" +msgstr "Rétrogradation" + +#: includes/class-wc-subscriptions-switcher.php:1493 +msgid "There was an error locating the switch details." +msgstr "" +"Une erreur est survenue lors de la localisation des détails du changement." + +#: includes/class-wc-subscriptions-switcher.php:1452 +msgid "" +"You can not switch this subscription. It appears you do not own the " +"subscription." +msgstr "" +"Vous ne pouvez pas changer cet abonnement. Il semble que cet abonnement ne " +"vous appartient pas." + +#: includes/class-wc-subscriptions-switcher.php:1405 +msgid "You can not switch to the same subscription." +msgstr "Vous ne pouvez pas passer au même abonnement." + +#: includes/class-wc-subscriptions-switcher.php:1383 +msgid "We can not find your old subscription item." +msgstr "Nous ne trouvons pas votre ancien article d’abonnement." + +#: includes/class-wc-subscriptions-switcher.php:1211 +msgid "Switched Subscription" +msgstr "Abonnement changé" + +#: includes/class-wc-subscriptions-switcher.php:1196 +msgid "Switch Order" +msgstr "Commande de changement" + +#. translators: 1$: old item, 2$: new item when switching +#: includes/class-wc-subscriptions-switcher.php:1985 +msgctxt "used in order notes" +msgid "Customer switched from: %1$s to %2$s." +msgstr "Le client est passé de : %1$s à %2$s." + +#: includes/class-wc-subscriptions-switcher.php:444 +#: includes/class-wc-subscriptions-switcher.php:542 +#: includes/class-wc-subscriptions-switcher.php:2563 +msgid "Upgrade or Downgrade" +msgstr "Mettre à niveau ou rétrograder" + +#: includes/class-wc-subscriptions-switcher.php:440 +msgid "" +"Customise the text displayed on the button next to the subscription on the " +"subscriber's account page. The default is \"Switch Subscription\", but you " +"may wish to change this to \"Upgrade\" or \"Change Subscription\"." +msgstr "" +"Personnalisez le texte affiché sur le bouton en regard de l’abonnement sur " +"la page du compte de l’abonné. Le texte par défaut est « Changer " +"d’abonnement », mais vous pouvez le remplacer par « Mettre à niveau » ou " +"« Modifier l’abonnement »." + +#: includes/class-wc-subscriptions-switcher.php:439 +msgid "Switch Button Text" +msgstr "Texte du bouton de changement" + +#: includes/class-wc-subscriptions-switcher.php:424 +msgid "" +"When switching to a subscription with a length, you can take into account " +"the payments already completed by the customer when determining how many " +"payments the subscriber needs to make for the new subscription." +msgstr "" +"Lors du passage à un abonnement avec une durée, vous pouvez prendre en " +"compte les paiements déjà effectués par le client pour déterminer le nombre " +"de paiements que l’abonné doit effectuer pour le nouvel abonnement." + +#: includes/class-wc-subscriptions-switcher.php:423 +msgid "Prorate Subscription Length" +msgstr "Durée de l’abonnement au prorata" + +#: includes/class-wc-subscriptions-switcher.php:417 +msgctxt "when to prorate signup fee when switching" +msgid "Always" +msgstr "Toujours" + +#: includes/class-wc-subscriptions-switcher.php:416 +msgctxt "when to prorate signup fee when switching" +msgid "Never (charge the full sign up fee)" +msgstr "Jamais (facturer l’intégralité des frais d’inscription)" + +#: includes/class-wc-subscriptions-switcher.php:415 +msgctxt "when to prorate signup fee when switching" +msgid "Never (do not charge a sign up fee)" +msgstr "Jamais (ne pas facturer de frais d’inscription)" + +#: includes/class-wc-subscriptions-switcher.php:408 +msgid "" +"When switching to a subscription with a sign up fee, you can require the " +"customer pay only the gap between the existing subscription's sign up fee " +"and the new subscription's sign up fee (if any)." +msgstr "" +"Lors du passage à un abonnement avec des frais d’inscription, vous pouvez " +"demander au client de ne payer que l’écart entre les frais d’inscription de " +"l’abonnement existant et ceux du nouvel abonnement (le cas échéant)." + +#: includes/class-wc-subscriptions-switcher.php:407 +msgid "Prorate Sign up Fee" +msgstr "Frais d’inscription au prorata" + +#: includes/class-wc-subscriptions-switcher.php:401 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of All Subscription Products" +msgstr "" +"Pour les mises à niveau et les rétrogradations de tous les produits " +"d’abonnement" + +#: includes/class-wc-subscriptions-switcher.php:400 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of Virtual Subscription Products Only" +msgstr "" +"Pour les mises à niveau et les rétrogradations des produits d’abonnement " +"virtuels uniquement" + +#: includes/class-wc-subscriptions-switcher.php:399 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of All Subscription Products" +msgstr "Pour les mises à niveau de tous les produits d’abonnement" + +#: includes/class-wc-subscriptions-switcher.php:398 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of Virtual Subscription Products Only" +msgstr "Pour les mises à niveau des produits d’abonnement virtuels uniquement" + +#: includes/class-wc-subscriptions-switcher.php:390 +msgid "" +"When switching to a subscription with a different recurring payment or " +"billing period, should the price paid for the existing billing period be " +"prorated when switching to the new subscription?" +msgstr "" +"Lors du passage à un abonnement avec une période de paiement ou de " +"facturation récurrente différente, le prix payé pour la période de " +"facturation existante doit-il être calculé au prorata lors du passage au " +"nouvel abonnement ?" + +#: includes/class-wc-subscriptions-switcher.php:389 +msgid "Prorate Recurring Payment" +msgstr "Paiement récurrent au prorata" + +#: includes/class-wc-subscriptions-switcher.php:490 +msgctxt "when to allow switching" +msgid "Between Grouped Subscriptions" +msgstr "Entre des abonnements groupés" + +#: includes/class-wc-subscriptions-switcher.php:486 +msgctxt "when to allow switching" +msgid "Between Subscription Variations" +msgstr "Entre des variantes d’abonnement" + +#: includes/class-wc-subscriptions-switcher.php:397 +#: includes/class-wc-subscriptions-switcher.php:431 +msgctxt "when to allow a setting" +msgid "Never" +msgstr "Jamais" + +#: includes/class-wc-subscriptions-switcher.php:479 +msgid "Allow Switching" +msgstr "Autoriser le changement" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-switcher.php:379 +msgid "" +"Allow subscribers to switch (upgrade or downgrade) between different " +"subscriptions. %1$sLearn more%2$s." +msgstr "" +"Autorisez les abonnés à basculer (mettre à niveau ou rétrograder) entre " +"différents abonnements. %1$sEn savoir plus%2$s." + +#: includes/class-wc-subscriptions-switcher.php:376 +msgid "Switching" +msgstr "Changement" + +#. translators: 1$: is the "You have already subscribed to this product" +#. notice, 2$-4$: opening/closing link tags, 3$: an order number +#: includes/class-wc-subscriptions-switcher.php:281 +msgid "" +"%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your " +"subscription." +msgstr "" +"%1$s Effectuez le paiement sur la %2$scommande %3$s%4$s pour pouvoir changer " +"votre abonnement." + +#: includes/class-wc-subscriptions-switcher.php:272 +msgid "" +"You have already subscribed to this product and it is limited to one per " +"customer. You can not purchase the product again." +msgstr "" +"Vous êtes déjà abonné à ce produit et il est limité à un par client. Vous ne " +"pouvez pas racheter le produit." + +#: includes/class-wc-subscriptions-switcher.php:230 +#: includes/class-wc-subscriptions-switcher.php:1249 +msgid "" +"Your cart contained an invalid subscription switch request. It has been " +"removed." +msgid_plural "" +"Your cart contained invalid subscription switch requests. They have been " +"removed." +msgstr[0] "" +"Votre panier contenait une demande de changement d’abonnement non valide. " +"Elle a été supprimée." +msgstr[1] "" +"Votre panier contenait des demandes de changement d’abonnement non valides. " +"Elles ont été supprimées." + +#: includes/class-wc-subscriptions-switcher.php:190 +msgid "Choose a new subscription." +msgstr "Choisissez un nouvel abonnement." + +#: includes/class-wc-subscriptions-switcher.php:188 +msgid "" +"You have a subscription to this product. Choosing a new subscription will " +"replace your existing subscription." +msgstr "" +"Vous avez un abonnement à ce produit. Choisir un nouvel abonnement " +"remplacera votre abonnement existant." + +#: includes/class-wc-subscriptions-renewal-order.php:181 +msgid "Subscription renewal orders cannot be cancelled." +msgstr "" +"Les commandes de renouvellement d’abonnement ne peuvent pas être annulées." + +#. translators: placeholder is order ID +#: includes/class-wc-subscriptions-renewal-order.php:161 +msgid "Order %s created to record renewal." +msgstr "Commande %s créée pour enregistrer le renouvellement." + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years +#. for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a +#. $30 sign-up fee"). +#: includes/class-wc-subscriptions-product.php:398 +msgid "%1$s and a %2$s sign-up fee" +msgstr "%1$s et des frais d’inscription de %2$s" + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years +#. for 6 years"), 2$: trial length (e.g.: "with 4 months free trial"). +#: includes/class-wc-subscriptions-product.php:393 +msgid "%1$s with %2$s free trial" +msgstr "%1$s avec un essai gratuit de %2$s" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March +#. 23rd every 3rd year"), 2$: length (e.g. "4 years"). +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March +#. 23rd every 3rd year"), 2$: length (e.g. "4 years") +#: includes/class-wc-subscriptions-product.php:387 +#: includes/wcs-formatting-functions.php:209 +msgid "%1$s for %2$s" +msgstr "%1$s pour %2$s" + +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or +#. "3 months") (e.g. "$15 / month" or "$15 every 2nd month"). +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or +#. "3 months") (e.g. "$15 / month" or "$15 every 2nd month") +#: includes/class-wc-subscriptions-product.php:367 +#: includes/wcs-formatting-functions.php:198 +msgid "%1$s / %2$s" +msgid_plural "%1$s every %2$s" +msgstr[0] "%1$s / %2$s" +msgstr[1] "%1$s chaque %2$s" + +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the +#. month (e.g. "23rd"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the +#. month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: includes/class-wc-subscriptions-product.php:355 +#: includes/wcs-formatting-functions.php:187 +msgid "%1$s on %2$s %3$s every %4$s year" +msgstr "%1$s le %2$s %3$s chaque %4$s année" + +#. translators: 1$: on, 2$: , 3$: each year (e.g. "$15 on +#. March 15th each year"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the +#. month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: includes/class-wc-subscriptions-product.php:347 +#: includes/wcs-formatting-functions.php:178 +msgid "%1$s on %2$s %3$s each year" +msgstr "%1$s le %2$s %3$s chaque année" + +#. translators: 1$: on the, 2$: day of every, 3$: +#. month (e.g. "$10 on the 23rd day of every 2nd month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. +#. "$5 every 23rd of each month") +#: includes/class-wc-subscriptions-product.php:335 +#: includes/wcs-formatting-functions.php:165 +msgid "%1$s on the %2$s day of every %3$s month" +msgstr "%1$s le %2$s jour de chaque %3$s mois" + +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on +#. the last day of every 3rd month"). +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on +#. the last day of every 3rd month") +#: includes/class-wc-subscriptions-product.php:328 +#: includes/wcs-formatting-functions.php:162 +msgid "%1$s on the last day of every %2$s month" +msgstr "%1$s le dernier jour de chaque %2$s mois" + +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. +#. "$5 every 23rd of each month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. +#. "$5 every 23rd of each month") +#: includes/class-wc-subscriptions-product.php:319 +#: includes/wcs-formatting-functions.php:146 +msgid "%1$s on the %2$s of each month" +msgstr "%1$s le %2$s de chaque mois" + +#. translators: placeholder is recurring amount. +#. translators: placeholder is recurring amount +#: includes/class-wc-subscriptions-product.php:315 +#: includes/wcs-formatting-functions.php:143 +msgid "%s on the last day of each month" +msgstr "%s le dernier jour de chaque mois" + +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week +#. (e.g. "$10 every 2nd week on Wednesday"). +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week +#. (e.g. "$10 every 2nd week on Wednesday") +#: includes/class-wc-subscriptions-product.php:304 +#: includes/wcs-formatting-functions.php:125 +msgid "%1$s every %2$s on %3$s" +msgstr "%1$s chaque %2$s le %3$s" + +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 +#. every Wednesday"). +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 +#. every Wednesday") +#. translators: %1$: recurring amount (e.g. "$15"), %2$: subscription period +#. (e.g. "month") (e.g. "$15 every 2nd month") +#: includes/class-wc-subscriptions-product.php:300 +#: includes/wcs-formatting-functions.php:116 +#: includes/wcs-formatting-functions.php:201 +msgid "%1$s every %2$s" +msgstr "%1$s chaque %2$s" + +#: includes/class-wc-subscriptions-order.php:748 +msgctxt "An order type" +msgid "Original" +msgstr "Taille d’origine" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-order.php:386 +msgid "View the status of your subscription in %1$syour account%2$s." +msgid_plural "View the status of your subscriptions in %1$syour account%2$s." +msgstr[0] "Affichez l’état de votre abonnement dans %1$svotre compte%2$s." +msgstr[1] "Affichez l’état de vos abonnements dans %1$svotre compte%2$s." + +#: includes/class-wc-subscriptions-order.php:379 +msgid "Your subscription will be activated when payment clears." +msgid_plural "Your subscriptions will be activated when payment clears." +msgstr[0] "Votre abonnement sera activé une fois le paiement effectué." +msgstr[1] "Vos abonnements seront activés une fois le paiement effectué." + +#: includes/class-wc-subscriptions-manager.php:2310 +msgid "Date Changed" +msgstr "Date de modification" + +#: includes/class-wc-subscriptions-manager.php:2285 +msgid "Please enter all date fields." +msgstr "Veuillez saisir tous les champs de date." + +#: includes/class-wc-subscriptions-manager.php:2281 +msgid "Only store managers can edit payment dates." +msgstr "Seuls les gérants de boutique peuvent modifier les dates de paiement." + +#: includes/class-wc-subscriptions-manager.php:2277 +msgid "Invalid security token, please reload the page and try again." +msgstr "Jeton de sécurité non valide, veuillez recharger la page et réessayer." + +#. translators: placeholder is subscription ID +#: includes/class-wc-subscriptions-manager.php:2186 +msgid "Failed sign-up for subscription %s." +msgstr "Échec de l’inscription pour l’abonnement %s." + +#: includes/class-wc-subscriptions-manager.php:1853 +msgid "Change" +msgstr "Modifier" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, +#. 3$: year input. Change the order if you'd like +#: includes/class-wc-subscriptions-manager.php:1848 +msgid "%1$s%2$s, %3$s" +msgstr "%1$s%2$s, %3$s" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, +#. 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd +#. like +#: includes/class-wc-subscriptions-manager.php:1844 +msgid "%1$s%2$s, %3$s @ %4$s : %5$s" +msgstr "%1$s%2$s, %3$s @ %4$s : %5$s" + +#. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. +#. "Jan") +#: includes/class-wc-subscriptions-manager.php:1831 +msgctxt "used in a select box" +msgid "%1$s-%2$s" +msgstr "%1$s-%2$s" + +#: includes/class-wc-subscriptions-manager.php:567 +msgid "Pending subscription created." +msgstr "Abonnement en attente créé." + +#: includes/class-wc-subscriptions-manager.php:522 +msgid "Error: Unable to add product to created subscription. Please try again." +msgstr "" +"Erreur : Impossible d’ajouter le produit à l’abonnement créé. Veuillez " +"réessayer." + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:426 +msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" +msgstr "" +"Échec du traitement du paiement échoué de l’abonnement pour la commande " +"n°%1$s : %2$s" + +#: includes/class-wc-subscriptions-manager.php:416 +msgid "Subscription sign up failed." +msgstr "Échec de l’inscription à l’abonnement." + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:390 +msgid "Failed to set subscription as expired for order #%1$s: %2$s" +msgstr "" +"Échec du marquage de l’abonnement comme expiré pour la commande n°%1$s : %2$s" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:362 +msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" +msgstr "" +"Échec de l’annulation de l’abonnement après l’annulation de la commande " +"n°%1$s : %2$s" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:334 +msgid "" +"Failed to update subscription status after order #%1$s was put on-hold: %2$s" +msgstr "" +"Échec de la mise à jour de l’état de l’abonnement après la mise en attente " +"de la commande n°%1$s : %2$s" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:306 +msgid "Failed to activate subscription status for order #%1$s: %2$s" +msgstr "" +"Échec de l’activation de l’état de l’abonnement pour la commande n°%1$s: %2$s" + +#: includes/class-wc-subscriptions-coupon.php:479 +msgid "" +"Sorry, this coupon is only valid for subscription products with a sign-up " +"fee." +msgstr "" +"Désolé, ce code promo n’est valide que pour les produits d’abonnement avec " +"des frais d’inscription." + +#: includes/class-wc-subscriptions-coupon.php:468 +msgid "Sorry, this coupon is only valid for subscription products." +msgstr "Désolé, ce code promo n’est valide que pour les produits d’abonnement." + +#: includes/class-wc-subscriptions-coupon.php:463 +msgid "Sorry, this coupon is only valid for new subscriptions." +msgstr "Désolé, ce code promo n’est valide que pour les nouveaux abonnements." + +#: includes/class-wc-subscriptions-coupon.php:457 +msgid "" +"Sorry, this coupon is only valid for an initial payment and the cart does " +"not require an initial payment." +msgstr "" +"Désolé, ce code promo n’est valide que pour un paiement initial et le " +"produit ne nécessite pas de paiement initial." + +#: includes/class-wc-subscriptions-coupon.php:167 +msgid "Recurring Product % Discount" +msgstr "% de remise sur les produits récurrents" + +#: includes/class-wc-subscriptions-coupon.php:166 +msgid "Recurring Product Discount" +msgstr "Remise sur les produits récurrents" + +#: includes/class-wc-subscriptions-coupon.php:165 +msgid "Sign Up Fee % Discount" +msgstr "% de remise sur les frais d’inscription" + +#: includes/class-wc-subscriptions-coupon.php:164 +msgid "Sign Up Fee Discount" +msgstr "Remise sur les frais d’inscription" + +#: includes/class-wc-subscriptions-manager.php:500 +msgid "Error: Unable to create subscription. Please try again." +msgstr "Erreur : Impossible de créer l’abonnement. Veuillez réessayer." + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:225 +msgid "Error %d: Unable to create order. Please try again." +msgstr "Erreur %d : Impossible de créer la commande. Veuillez réessayer." + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:196 +#: includes/class-wc-subscriptions-checkout.php:389 +msgid "Error %d: Unable to create subscription. Please try again." +msgstr "Erreur %d : Impossible de créer l’abonnement. Veuillez réessayer." + +#. translators: 1: old payment title, 2: new payment title. +#: includes/class-wc-subscriptions-change-payment-gateway.php:534 +msgctxt "%1$s: old payment title, %2$s: new payment title" +msgid "" +"Payment method changed from \"%1$s\" to \"%2$s\" by the subscriber from " +"their account page." +msgstr "" +"Le moyen de paiement est passé de « %1$s » à « %2$s » par l’abonné sur sa " +"page de compte." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:340 +msgid "Payment method updated." +msgstr "Moyen de paiement mis à jour." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:259 +msgid "Invalid order." +msgstr "Commande non valide." + +#. translators: placeholder is either empty or "Next payment is due..." +#: includes/class-wc-subscriptions-change-payment-gateway.php:211 +msgid "Choose a new payment method.%s" +msgstr "Choisissez un nouveau moyen de paiement.%s" + +#. translators: placeholder is next payment's date +#: includes/class-wc-subscriptions-change-payment-gateway.php:205 +msgid " Next payment is due %s." +msgstr " Le prochain paiement est dû le %s." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:256 +#: includes/class-wcs-query.php:243 +msgid "The payment method can not be changed for that subscription." +msgstr "Le moyen de paiement ne peut pas être modifié pour cet abonnement." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:253 +#: includes/class-wcs-cart-resubscribe.php:78 +#: includes/class-wcs-cart-resubscribe.php:129 +#: includes/class-wcs-user-change-status-handler.php:111 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:95 +msgid "That doesn't appear to be one of your subscriptions." +msgstr "Cela ne semble pas être l’un de vos abonnements." + +#: includes/api/class-wc-rest-subscriptions-controller.php:293 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:172 +msgid "Invalid subscription id." +msgstr "ID d’abonnement non valide." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:247 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:106 +msgid "There was an error with your request. Please try again." +msgstr "Une erreur est survenue lors de votre demande. Veuillez réessayer." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:181 +msgid "" +"Sorry, this subscription change payment method request is invalid and cannot " +"be processed." +msgstr "" +"Désolé, cette demande de changement de moyen de paiement pour l’abonnement " +"n’est pas valide et ne peut pas être traitée." + +#. translators: placeholder is the display name of the payment method +#: templates/checkout/subscription-receipt.php:37 +msgid "Payment Method: %s" +msgstr "Moyen de paiement : %s" + +#. translators: placeholder is the subscription's next payment date (either +#. human readable or normal date) wrapped in tags +#: templates/checkout/subscription-receipt.php:24 +msgid "Next Payment Date: %s" +msgstr "Date du prochain paiement : %s" + +#: includes/privacy/class-wcs-privacy-exporters.php:77 +msgid "Subscription Number" +msgstr "Numéro d’abonnement" + +#: includes/class-wc-subscriptions-cart.php:2218 +msgid "now" +msgstr "maintenant" + +#: includes/class-wc-subscriptions-cart-validator.php:136 +#: includes/class-wc-subscriptions-cart.php:1542 +msgid "" +"That subscription product can not be added to your cart as it already " +"contains a subscription renewal." +msgstr "" +"Ce produit d’abonnement ne peut pas être ajouté à votre panier car il " +"contient déjà un renouvellement d’abonnement." + +#: includes/class-wc-subscriptions-cart.php:995 +msgid "Please enter a valid postcode/ZIP." +msgstr "Veuillez saisir un code postal valide." + +#. translators: $1: address type (Shipping Address / Billing Address), $2: +#. opening tag, $3: closing tag +#: includes/class-wc-subscriptions-addresses.php:84 +msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" +msgstr "Mettre à jour l’%1$s utilisée pour %2$stous%3$s mes abonnements actifs" + +#: includes/class-wc-subscriptions-addresses.php:71 +msgid "" +"Both the shipping address used for the subscription and your default " +"shipping address for future purchases will be updated." +msgstr "" +"L’adresse de livraison utilisée pour l’abonnement et votre adresse de " +"livraison par défaut pour les achats futurs seront mises à jour." + +#: includes/class-wc-subscriptions-addresses.php:47 +msgid "Change address" +msgstr "Modifier l’adresse" + +#: includes/class-wc-subscription.php:2098 wcs-functions.php:828 +msgid "Payment method meta must be an array." +msgstr "Les métadonnées du moyen de paiement doivent être un tableau." + +#: includes/admin/class-wcs-admin-post-types.php:961 +#: includes/class-wc-subscription.php:2007 +#: includes/class-wcs-change-payment-method-admin.php:168 +msgid "Manual Renewal" +msgstr "Renouvellement manuel" + +#: includes/class-wc-subscription.php:1790 +msgid "Subscription Cancelled: maximum number of failed payments reached." +msgstr "Abonnement annulé : nombre maximal d’échecs de paiement atteint." + +#: includes/class-wc-subscription.php:1785 +msgid "Payment failed." +msgstr "Échec du paiement." + +#. translators: %s: date type (e.g. "trial_end"). +#: includes/class-wc-subscription.php:1334 +msgid "" +"The %s date of a subscription can not be deleted. You must delete the order." +msgstr "" +"La date de %s d’un abonnement ne peut pas être supprimée. Vous devez " +"supprimer la commande." + +#: includes/class-wc-subscription.php:1329 +msgid "The start date of a subscription can not be deleted, only updated." +msgstr "" +"La date de début d’un abonnement ne peut pas être supprimée, uniquement mise " +"à jour." + +#. translators: %s: date type (e.g. "next_payment"). +#: includes/class-wc-subscription.php:2432 +msgid "The %s date must occur after the start date." +msgstr "La date de %s doit être postérieure à la date de début." + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2427 +msgid "The %s date must occur after the trial end date." +msgstr "La date de %s doit être postérieure à la date de fin d’essai." + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2421 +msgid "The %s date must occur after the next payment date." +msgstr "La date de %s doit être postérieure à la date du prochain paiement." + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2416 +msgid "The %s date must occur after the last payment date." +msgstr "La date de %s doit être postérieure à la date du dernier paiement." + +#. translators: placeholder is date type (e.g. "end", "next_payment"...) +#: includes/class-wc-subscription.php:2372 +msgctxt "appears in an error message if date is wrong format" +msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"." +msgstr "Date %s non valide. La date doit être au format : « Y-m-d H:i:s »." + +#: includes/class-wc-subscription.php:2345 +msgid "" +"Invalid data. First parameter has a date that is not in the registered date " +"types." +msgstr "" +"Données non valides. Le premier paramètre a une date qui n’est pas dans les " +"types de date enregistrés." + +#: includes/class-wc-subscription.php:2338 +msgid "Invalid data. First parameter was empty when passed to update_dates()." +msgstr "" +"Données non valides. Le premier paramètre était vide lorsqu’il a été passé à " +"update_dates()." + +#: includes/class-wc-subscription.php:2334 +msgid "Invalid format. First parameter needs to be an array." +msgstr "Format non valide. Le premier paramètre doit être un tableau." + +#: includes/class-wc-subscription.php:1218 +msgctxt "original denotes there is no date to display" +msgid "-" +msgstr "-" + +#: includes/class-wc-subscription.php:1210 +msgid "Not yet ended" +msgstr "Pas encore terminé" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/class-wc-subscription.php:1203 +#: includes/wcs-formatting-functions.php:246 +msgid "%s ago" +msgstr "il y a %s" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/class-wc-subscription.php:1200 +#: includes/class-wc-subscriptions-manager.php:2304 +msgid "In %s" +msgstr "Dans %s" + +#. translators: 1: old subscription status 2: new subscription status +#: includes/class-wc-subscription.php:576 +msgid "Status changed from %1$s to %2$s." +msgstr "État passé de %1$s à %2$s." + +#. translators: %s: subscription status. +#: includes/class-wc-subscription.php:423 +msgid "Unable to change subscription status to \"%s\"." +msgstr "Impossible de modifier l’état d’abonnement sur « %s »." + +#: includes/api/legacy/class-wc-api-subscriptions.php:398 wcs-functions.php:147 +msgid "Invalid subscription billing period given." +msgstr "Période de facturation de l’abonnement donnée non valide." + +#: includes/api/legacy/class-wc-api-subscriptions.php:387 wcs-functions.php:152 +msgid "" +"Invalid subscription billing interval given. Must be an integer greater than " +"0." +msgstr "" +"Intervalle de facturation de l’abonnement donné non valide. Doit être un " +"entier supérieur à 0." + +#. translators: 1$: gateway id, 2$: error message +#: includes/api/legacy/class-wc-api-subscriptions.php:352 +msgid "" +"Subscription payment method could not be set to %1$s and has been set to " +"manual with error message: %2$s" +msgstr "" +"Le moyen de paiement de l’abonnement n’a pas pu être défini sur %1$s et a " +"été défini sur manuel avec le message d’erreur : %2$s" + +#: includes/api/class-wc-rest-subscriptions-controller.php:364 +#: includes/api/legacy/class-wc-api-subscriptions.php:314 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:306 +msgid "" +"Gateway does not support admin changing the payment method on a Subscription." +msgstr "" +"La passerelle ne prend pas en charge la modification par l’administrateur du " +"moyen de paiement sur un abonnement." + +#: includes/api/legacy/class-wc-api-subscriptions.php:248 +msgid "The requested subscription cannot be edited." +msgstr "L’abonnement demandé ne peut pas être modifié." + +#: includes/api/legacy/class-wc-api-subscriptions.php:173 +msgid "You do not have permission to create subscriptions" +msgstr "Vous n’avez pas le droit de créer des abonnements" + +#: includes/api/legacy/class-wc-api-subscriptions.php:124 +msgid "You do not have permission to read the subscriptions count" +msgstr "Vous n’avez pas le droit de lire le comptage des abonnements" + +#: includes/api/legacy/class-wc-api-subscriptions.php:102 wcs-functions.php:178 +msgid "Invalid subscription status given." +msgstr "État d’abonnement donné non valide." + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Error: unable to find timezone of your browser." +msgstr "Erreur : le fuseau horaire de votre navigateur est introuvable." + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Timezone:" +msgstr "Fuseau horaire :" + +#: templates/admin/html-variation-price.php:56 +msgid "Billing Period:" +msgstr "Période de facturation :" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:43 +msgid "Recurring:" +msgstr "Récurrent :" + +#: includes/admin/class-wcs-admin-post-types.php:425 +msgid "Total" +msgstr "Total" + +#: includes/admin/class-wcs-admin-post-types.php:422 +#: includes/admin/meta-boxes/views/html-related-orders-table.php:20 +#: templates/myaccount/my-subscriptions.php:22 +#: templates/myaccount/my-subscriptions.php:37 +#: templates/myaccount/related-orders.php:24 +#: templates/myaccount/related-orders.php:50 +#: templates/myaccount/related-subscriptions.php:22 +#: templates/myaccount/related-subscriptions.php:36 +#: templates/myaccount/subscription-details.php:18 +msgid "Status" +msgstr "État" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:19 +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:776 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:195 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:209 +#: templates/myaccount/related-orders.php:23 +#: templates/myaccount/related-orders.php:47 +msgid "Date" +msgstr "Date" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:18 +msgid "Relationship" +msgstr "Relation" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:17 +#: templates/myaccount/related-orders.php:42 +msgid "Order Number" +msgstr "Numéro de commande" + +#: includes/admin/meta-boxes/views/html-related-orders-row.php:36 +#: includes/admin/meta-boxes/views/html-retries-table.php:47 +msgid "Unpublished" +msgstr "Non publié" + +#. translators: php date format +#: includes/admin/meta-boxes/views/html-related-orders-row.php:33 +#: includes/admin/meta-boxes/views/html-retries-table.php:44 +msgctxt "post date" +msgid "Y/m/d g:i:s A" +msgstr "" +"d/m/Y à G h i mi\n" +" s s" + +#. translators: placeholder is an order number. +#. translators: placeholder is an order ID. +#. translators: %s: order number. +#. translators: %s: order ID. +#: includes/admin/meta-boxes/views/html-related-orders-row.php:21 +#: includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:18 +#: includes/class-wc-subscriptions-renewal-order.php:158 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:309 +#: includes/early-renewal/wcs-early-renewal-functions.php:162 +#: templates/myaccount/my-subscriptions.php:34 +#: templates/myaccount/related-orders.php:44 +#: templates/myaccount/related-subscriptions.php:33 +msgctxt "hash before order number" +msgid "#%s" +msgstr "n°%s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:295 +msgid "Customer's notes about the order" +msgstr "Notes du client à propos de la commande" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "No shipping address set." +msgstr "Aucune adresse de livraison." + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:170 +#: includes/class-wcs-change-payment-method-admin.php:38 +#: includes/class-wcs-change-payment-method-admin.php:51 +msgid "Payment Method" +msgstr "Moyen de paiement" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +msgid "No billing address set." +msgstr "Aucune adresse de facturation." + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:148 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:240 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "Address" +msgstr "Adresse" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:93 +msgid "Subscription status:" +msgstr "État de l’abonnement :" + +#: includes/admin/class-wcs-admin-post-types.php:1114 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:85 +msgid "Search for a customer…" +msgstr "Recherche d’un client…" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:55 +msgid "Customer:" +msgstr "Client :" + +#. translators: placeholder is the ID of the subscription +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:48 +msgctxt "edit subscription header" +msgid "Subscription #%s details" +msgstr "Détails de l’abonnement n°%s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:93 +msgctxt "relation to order" +msgid "Renewal Order" +msgstr "Commande de renouvellement" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:96 +msgctxt "relation to order" +msgid "Parent Order" +msgstr "Commande parente" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:82 +msgctxt "relation to order" +msgid "Initial Subscription" +msgstr "Abonnement initial" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribed Subscription" +msgstr "Abonnement réabonné" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:77 +msgctxt "relation to order" +msgid "Subscription" +msgstr "Abonnement" + +#: includes/admin/class-wcs-admin-post-types.php:955 +msgid "None" +msgstr "Aucun" + +#: includes/admin/class-wcs-admin-post-types.php:954 +msgid "Any Payment Method" +msgstr "Tout moyen de paiement" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:918 +msgid "Subscription draft updated." +msgstr "Brouillon d’abonnement mis à jour." + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:917 +msgctxt "used in \"Subscription scheduled for \"" +msgid "M j, Y @ G:i" +msgstr "j M Y @ G:i" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:917 +msgid "Subscription scheduled for: %1$s." +msgstr "Abonnement planifié pour : %1$s." + +#: includes/admin/class-wcs-admin-post-types.php:915 +msgid "Subscription submitted." +msgstr "Abonnement envoyé." + +#: includes/admin/class-wcs-admin-post-types.php:914 +msgid "Subscription saved." +msgstr "Abonnement enregistré." + +#. translators: placeholder is previous post title +#: includes/admin/class-wcs-admin-post-types.php:912 +msgctxt "used in post updated messages" +msgid "Subscription restored to revision from %s" +msgstr "Abonnement restauré à la révision à partir de %s" + +#: includes/admin/class-wcs-admin-post-types.php:909 +msgid "Custom field deleted." +msgstr "Champ personnalisé supprimé." + +#: includes/admin/class-wcs-admin-post-types.php:908 +msgid "Custom field updated." +msgstr "Champ personnalisé mis à jour." + +#. translators: placeholder is previous post title +#: includes/admin/class-wcs-admin-post-types.php:907 +#: includes/admin/class-wcs-admin-post-types.php:910 +#: includes/admin/class-wcs-admin-post-types.php:913 +msgid "Subscription updated." +msgstr "Abonnement mis à jour." + +#. translators: %d: item count. +#: includes/admin/class-wcs-admin-post-types.php:590 +msgid "%d item" +msgid_plural "%d items" +msgstr[0] "%d élément" +msgstr[1] "%d éléments" + +#: includes/admin/class-wcs-admin-post-types.php:527 +msgctxt "meaning billing address" +msgid "Billing:" +msgstr "Facturation :" + +#: includes/admin/class-wcs-admin-post-types.php:499 +msgid "Cancel Now" +msgstr "Annuler maintenant" + +#: includes/admin/class-wcs-admin-post-types.php:493 +msgid "Delete this item permanently" +msgstr "Supprimer cet article définitivement" + +#: includes/admin/class-wcs-admin-post-types.php:489 +msgid "Move this item to the Trash" +msgstr "Déplacer cet article vers la corbeille" + +#: includes/admin/class-wcs-admin-post-types.php:487 +#: includes/class-wc-subscriptions-product.php:767 +msgid "Restore" +msgstr "Restaurer" + +#: includes/admin/class-wcs-admin-post-types.php:487 +#: includes/class-wc-subscriptions-product.php:766 +msgid "Restore this item from the Trash" +msgstr "Restaurer cet article depuis la corbeille" + +#: includes/admin/class-wcs-admin-post-types.php:475 +#: includes/admin/class-wcs-admin-post-types.php:493 +msgid "Delete Permanently" +msgstr "Supprimer définitivement" + +#: includes/admin/class-wcs-admin-post-types.php:474 +#: includes/admin/class-wcs-admin-post-types.php:489 +msgid "Trash" +msgstr "Corbeille" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:367 +msgid "Cancel" +msgstr "Annuler" + +#: includes/admin/class-wcs-admin-post-types.php:472 +#: includes/wcs-user-functions.php:333 +msgid "Suspend" +msgstr "Suspendre" + +#: includes/admin/class-wcs-admin-post-types.php:471 +#: includes/wcs-user-functions.php:338 +msgid "Reactivate" +msgstr "Réactiver" + +#. translators: 1$: is the number of subscriptions not updated, 2$: is the +#. error message +#: includes/admin/class-wcs-admin-post-types.php:398 +msgid "%1$s subscription could not be updated: %2$s" +msgid_plural "%1$s subscriptions could not be updated: %2$s" +msgstr[0] "%1$s abonnement n’a pas pu être mis à jour : %2$s" +msgstr[1] "%1$s abonnements n’ont pas pu être mis à jour : %2$s" + +#. translators: placeholder is the number of subscriptions updated +#: includes/admin/class-wcs-admin-post-types.php:391 +msgid "%s subscription status changed." +msgid_plural "%s subscription statuses changed." +msgstr[0] "%s état d’abonnement modifié." +msgstr[1] "%s états d’abonnement modifiés." + +#: includes/admin/class-wcs-admin-post-types.php:259 +msgctxt "an action on a subscription" +msgid "Put on-hold" +msgstr "Mettre en attente" + +#: includes/admin/class-wcs-admin-post-types.php:214 +msgid "Search for a product…" +msgstr "Rechercher un produit…" + +#: includes/admin/class-wcs-admin-meta-boxes.php:211 +msgid "Create pending renewal order requested by admin action." +msgstr "" +"Créez une commande de renouvellement en attente demandée par une action de " +"l’administrateur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:200 +msgid "Process renewal order action requested by admin." +msgstr "" +"Traitez l’action de commande de renouvellement demandée par l’administrateur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:181 +msgid "Create pending renewal order" +msgstr "Créer une commande de renouvellement en attente" + +#: includes/admin/class-wcs-admin-meta-boxes.php:177 +msgid "Process renewal" +msgstr "Traiter le renouvellement" + +#: includes/admin/class-wcs-admin-meta-boxes.php:130 +msgid "" +"Are you sure you want to process a renewal?\n" +"\n" +"This will charge the customer and email them the renewal order (if emails " +"are enabled)." +msgstr "" +"Voulez-vous vraiment traiter un renouvellement ?\n" +"\n" +"Cela facturera le client et lui enverra la commande de renouvellement par e-" +"mail (si les e-mails sont activés)." + +#: includes/admin/class-wcs-admin-meta-boxes.php:129 +msgid "Please enter a date after the next payment." +msgstr "Veuillez saisir une date après le prochain paiement." + +#: includes/admin/class-wcs-admin-meta-boxes.php:128 +msgid "Please enter a date before the next payment." +msgstr "Veuillez saisir une date avant le prochain paiement." + +#: includes/admin/class-wcs-admin-meta-boxes.php:126 +#: includes/admin/class-wcs-admin-meta-boxes.php:127 +msgid "Please enter a date after the start date." +msgstr "Veuillez saisir une date après la date de début." + +#: includes/admin/class-wcs-admin-meta-boxes.php:125 +msgid "Please enter a date after the trial end." +msgstr "Veuillez saisir une date après la fin de l’essai." + +#: includes/admin/class-wcs-admin-meta-boxes.php:124 +msgid "Please enter a date at least one hour into the future." +msgstr "Veuillez saisir une date au moins une heure dans le futur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:123 +msgid "Please enter a start date in the past." +msgstr "Veuillez saisir une date de début dans le passé." + +#: includes/admin/class-wcs-admin-meta-boxes.php:73 +msgctxt "meta box title" +msgid "Subscription Data" +msgstr "Données d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:1791 +msgid "" +"Supports automatic renewal payments with the WooCommerce Subscriptions " +"extension." +msgstr "" +"Prend en charge les paiements de renouvellement automatiques avec " +"l’extension WooCommerce Subscriptions." + +#: includes/admin/class-wc-subscriptions-admin.php:1760 +msgid "Automatic Recurring Payments" +msgstr "Paiements récurrents automatiques" + +#: includes/admin/class-wc-subscriptions-admin.php:1730 +#: includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to live site" +msgid "Live" +msgstr "En direct" + +#: includes/admin/class-wc-subscriptions-admin.php:1730 +#: includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to staging site" +msgid "Staging" +msgstr "Préproduction" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:933 +msgid "Subscriptions Ended" +msgstr "Abonnements terminés" + +#: includes/admin/class-wc-subscriptions-admin.php:1724 +#: includes/admin/class-wcs-admin-system-status.php:95 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +msgid "No" +msgstr "Non" + +#: includes/admin/class-wc-subscriptions-admin.php:1724 +#: includes/admin/class-wc-subscriptions-admin.php:1791 +#: includes/admin/class-wcs-admin-system-status.php:95 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +msgid "Yes" +msgstr "Oui" + +#: includes/admin/class-wc-subscriptions-admin.php:1723 +#: includes/admin/class-wcs-admin-system-status.php:93 +msgctxt "label that indicates whether debugging is turned on for the plugin" +msgid "WCS_DEBUG" +msgstr "WCS_DEBUG" + +#. translators: placeholder is a time period (e.g. "4 weeks") +#: includes/admin/class-wc-subscriptions-admin.php:1661 +msgid "The trial period can not exceed %s." +msgstr "La période d’essai ne peut pas dépasser %s." + +#. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years +#: includes/admin/class-wc-subscriptions-admin.php:1656 +msgid "The trial period can not exceed: %1$s, %2$s, %3$s or %4$s." +msgstr "La période d’essai ne peut pas dépasser : %1$s, %2$s, %3$s ou %4$s." + +#. translators: placeholders are opening link tag, ID of sub, and closing link +#. tag +#: includes/admin/class-wc-subscriptions-admin.php:1627 +#: includes/admin/class-wc-subscriptions-admin.php:1632 +msgid "Showing orders for %1$sSubscription %2$s%3$s" +msgstr "Affichage des commandes pour %1$sAbonnement %2$s%3$s" + +#. translators: placeholder is a number +#: includes/admin/class-wc-subscriptions-admin.php:1497 +msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" +msgstr "" +"Nous ne trouvons pas d’abonnement avec l’ID n°%d. Peut-être a-t-il été " +"supprimé ?" + +#: includes/admin/class-wc-subscriptions-admin.php:1414 +#: includes/upgrades/templates/wcs-about-2-0.php:35 +#: includes/upgrades/templates/wcs-about.php:34 +#: woocommerce-subscriptions.php:1148 +msgid "Settings" +msgstr "Réglages" + +#: includes/admin/class-wc-subscriptions-admin.php:1413 +msgid "Add a Subscription Product" +msgstr "Ajouter un produit d’abonnement" + +#. translators: $1-$2: opening and closing tags, $3-$4: opening and +#. closing tags +#: includes/admin/class-wc-subscriptions-admin.php:1395 +msgid "" +"%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou're ready to " +"start selling subscriptions!%4$s" +msgstr "" +"%1$sWooCommerce Subscriptions installé%2$s – %3$sVous êtes prêt à " +"commencer à vendre des abonnements !%4$s" + +#. translators: $1-$2: opening and closing tags. Link to documents->payment +#. gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions +#. shop page +#: includes/admin/class-wc-subscriptions-admin.php:1932 +msgid "" +"Find new gateways that %1$ssupport automatic subscription payments%2$s in " +"the official %3$sWooCommerce Marketplace%4$s." +msgstr "" +"Trouvez de nouvelles passerelles %1$sprenant en charge les paiements " +"d’abonnement automatiques%2$s sur la %3$splace de marché officielle de " +"WooCommerce%4$s." + +#. translators: %s is a line break. +#: includes/admin/class-wc-subscriptions-admin.php:1354 +msgid "" +"Enabling this grants access to new downloadable files added to a product " +"only after the next renewal is processed.%sBy default, access to new " +"downloadable files added to a product is granted immediately to any customer " +"that has an active subscription with that product." +msgstr "" +"L’activation de cette option donne accès aux nouveaux fichiers " +"téléchargeables ajoutés à un produit uniquement après le traitement du " +"prochain renouvellement.%sPar défaut, l’accès aux nouveaux fichiers " +"téléchargeables ajoutés à un produit est accordé immédiatement à tout client " +"disposant d’un abonnement actif avec ce produit." + +#: includes/admin/class-wc-subscriptions-admin.php:1349 +msgid "Enable dripping for downloadable content on subscription products." +msgstr "" +"Activez la diffusion pour le contenu téléchargeable sur les produits " +"d’abonnement." + +#: includes/admin/class-wc-subscriptions-admin.php:1331 +msgid "" +"Allow multiple subscriptions and products to be purchased simultaneously." +msgstr "Autorisez l’achat simultané de plusieurs abonnements et produits." + +#: includes/admin/class-wc-subscriptions-admin.php:1330 +msgid "Mixed Checkout" +msgstr "Validation de commande mixte" + +#: includes/admin/class-wc-subscriptions-admin.php:1326 +msgid "" +"Set a maximum number of times a customer can suspend their account for each " +"billing period. For example, for a value of 3 and a subscription billed " +"yearly, if the customer has suspended their account 3 times, they will not " +"be presented with the option to suspend their account until the next year. " +"Store managers will always be able to suspend an active subscription. Set " +"this to 0 to turn off the customer suspension feature completely." +msgstr "" +"Définissez un nombre maximal de fois qu’un client peut suspendre son compte " +"pour chaque période de facturation. Par exemple, pour une valeur de 3 et un " +"abonnement facturé annuellement, si le client a suspendu son compte 3 fois, " +"il ne se verra pas proposer la possibilité de suspendre son compte jusqu’à " +"l’année suivante. Les gérants de boutique pourront toujours suspendre un " +"abonnement actif. Définissez ce paramètre sur 0 pour désactiver complètement " +"la fonctionnalité de suspension du client." + +#: includes/admin/class-wc-subscriptions-admin.php:1319 +msgid "Customer Suspensions" +msgstr "Suspensions de client" + +#: includes/admin/class-wc-subscriptions-admin.php:1312 +msgctxt "options section heading" +msgid "Miscellaneous" +msgstr "Divers" + +#: includes/admin/class-wc-subscriptions-admin.php:1296 +msgid "Turn off Automatic Payments" +msgstr "Désactiver les paiements automatiques" + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1290 +msgid "" +"With manual renewals, a customer's subscription is put on-hold until they " +"login and pay to renew it. %1$sLearn more%2$s." +msgstr "" +"Avec les renouvellements manuels, l’abonnement d’un client est mis en " +"attente jusqu’à ce qu’il se connecte et paie pour le renouveler. %1$sEn " +"savoir plus%2$s." + +#: includes/admin/class-wc-subscriptions-admin.php:1285 +msgid "Accept Manual Renewals" +msgstr "Accepter les renouvellements manuels" + +#: includes/admin/class-wc-subscriptions-admin.php:1284 +msgid "Manual Renewal Payments" +msgstr "Paiements de renouvellement manuels" + +#: includes/admin/class-wc-subscriptions-admin.php:1277 +msgctxt "option section heading" +msgid "Renewals" +msgstr "Renouvellements" + +#: includes/admin/class-wc-subscriptions-admin.php:1261 +msgid "" +"If a subscriber's subscription is manually cancelled or expires, she will be " +"assigned this role." +msgstr "" +"Si l’abonnement d’un abonné est annulé manuellement ou expire, ce rôle lui " +"sera attribué." + +#: includes/admin/class-wc-subscriptions-admin.php:1260 +msgid "Inactive Subscriber Role" +msgstr "Rôle d’abonné inactif" + +#: includes/admin/class-wc-subscriptions-admin.php:1249 +msgid "" +"When a subscription is activated, either manually or after a successful " +"purchase, new users will be assigned this role." +msgstr "" +"Lorsqu’un abonnement est activé, manuellement ou après un achat réussi, les " +"nouveaux utilisateurs se verront attribuer ce rôle." + +#: includes/admin/class-wc-subscriptions-admin.php:1248 +msgid "Subscriber Default Role" +msgstr "Rôle par défaut des abonnés" + +#. translators: placeholders are tags +#: includes/admin/class-wc-subscriptions-admin.php:1243 +msgid "" +"Choose the default roles to assign to active and inactive subscribers. For " +"record keeping purposes, a user account must be created for subscribers. " +"Users with the %1$sadministrator%2$s role, such as yourself, will never be " +"allocated these roles to prevent locking out administrators." +msgstr "" +"Choisissez les rôles par défaut à attribuer aux abonnés actifs et inactifs. " +"À des fins de tenue de rapports, un compte d’utilisateur doit être créé pour " +"les abonnés. Les utilisateurs avec le rôle %1$sadministrateur%2$s, comme " +"vous-même, ne se verront jamais attribuer ces rôles pour éviter le blocage " +"des administrateurs." + +#: includes/admin/class-wc-subscriptions-admin.php:1240 +msgid "Roles" +msgstr "Rôles" + +#: includes/admin/class-wc-subscriptions-admin.php:1224 +msgid "" +"Use this field to customise the text displayed on the checkout button when " +"an order contains a subscription. Normally the checkout submission button " +"displays \"Place order\". When the cart contains a subscription, this is " +"changed to \"Sign up now\"." +msgstr "" +"Utilisez ce champ pour personnaliser le libellé affiché sur le bouton de " +"paiement lorsqu’une commande contient un abonnement. Normalement, le bouton " +"d’envoi de la validation de commande affiche « Passer la commande ». Lorsque " +"le panier contient un abonnement, celui-ci devient « Inscription »." + +#: includes/admin/class-wc-subscriptions-admin.php:1223 +msgid "Place Order Button Text" +msgstr "Libellé du bouton Passer la commande" + +#: includes/admin/class-wc-subscriptions-admin.php:1216 +#: includes/admin/class-wc-subscriptions-admin.php:1219 +#: includes/admin/class-wc-subscriptions-admin.php:1228 +#: includes/admin/class-wc-subscriptions-admin.php:1231 +#: includes/class-wc-product-subscription-variation.php:98 +#: includes/class-wc-product-variable-subscription.php:73 +#: includes/class-wc-subscriptions-product.php:1196 +#: includes/class-wc-subscriptions-product.php:1214 +#: woocommerce-subscriptions.php:606 +msgid "Sign up now" +msgstr "Inscription" + +#: includes/admin/class-wc-subscriptions-admin.php:1212 +msgid "" +"A product displays a button with the text \"Add to cart\". By default, a " +"subscription changes this to \"Sign up now\". You can customise the button " +"text for subscriptions here." +msgstr "" +"Un produit affiche un bouton avec le libellé « Ajouter au panier ». Par " +"défaut, un abonnement remplace ce libellé par « Inscription ». Vous pouvez " +"personnaliser le libellé du bouton pour les abonnements ici." + +#: includes/admin/class-wc-subscriptions-admin.php:1211 +msgid "Add to Cart Button Text" +msgstr "Libellé du bouton Ajouter au panier" + +#: includes/admin/class-wc-subscriptions-admin.php:1204 +msgid "Button Text" +msgstr "Libellé du bouton" + +#: includes/admin/class-wc-subscriptions-admin.php:1012 +#: includes/admin/class-wc-subscriptions-admin.php:1164 +#: includes/admin/class-wcs-admin-reports.php:46 +#: includes/admin/class-wcs-admin-system-status.php:56 +#: includes/admin/class-wcs-wc-admin-manager.php:38 +#: includes/admin/class-wcs-wc-admin-manager.php:80 +#: includes/admin/class-wcs-wc-admin-manager.php:92 +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:917 +#: includes/class-wcs-query.php:108 includes/class-wcs-query.php:133 +#: includes/class-wcs-query.php:287 +#: includes/privacy/class-wcs-privacy-exporters.php:51 +#: woocommerce-subscriptions.php:266 woocommerce-subscriptions.php:279 +msgid "Subscriptions" +msgstr "Abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:990 +#: woocommerce-subscriptions.php:275 +msgid "Search Subscriptions" +msgstr "Rechercher des abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:986 +msgid "Manage Subscriptions" +msgstr "Gérer les abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:943 +msgid "Active subscriber?" +msgstr "Abonné actif ?" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: +#. "

    ", 3$: "

    ", 4$: "

    " +#: includes/admin/class-wc-subscriptions-admin.php:888 +msgctxt "" +"used in admin pointer script params in javascript as price pointer content" +msgid "" +"%1$sSet a Price%2$s%3$sSubscription prices are a little different to other " +"product prices. For a subscription, you can set a billing period, length, " +"sign-up fee and free trial.%4$s" +msgstr "" +"%1$sDéfinir un prix%2$s%3$sLes prix d’abonnement sont un peu différents des " +"prix des autres produits. Pour un abonnement, vous pouvez définir une " +"période de facturation, une durée, des frais d’inscription et un essai " +"gratuit.%4$s" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: +#. "

    ", 3$: "

    ", 4$: "", 5$: "", 6$: "", 7$: "", 8$: +#. "

    " +#: includes/admin/class-wc-subscriptions-admin.php:886 +msgctxt "" +"used in admin pointer script params in javascript as type pointer content" +msgid "" +"%1$sChoose Subscription%2$s%3$sThe WooCommerce Subscriptions extension adds " +"two new subscription product types - %4$sSimple subscription%5$s and " +"%6$sVariable subscription%7$s.%8$s" +msgstr "" +"%1$sChoisir l’abonnement%2$s%3$sL’extension WooCommerce Subscriptions ajoute " +"deux nouveaux types de produit d’abonnement : %4$sAbonnement simple%5$s et " +"%6$sAbonnement variable%7$s.%8$s" + +#: includes/admin/class-wc-subscriptions-admin.php:857 +msgid "" +"You are deleting a subscription item. You will also need to manually cancel " +"and trash the subscription on the Manage Subscriptions screen." +msgstr "" +"Vous supprimez un article d’abonnement. Vous devrez également annuler et " +"supprimer manuellement l’abonnement sur l’écran Gérer les abonnements." + +#: includes/admin/class-wc-subscriptions-admin.php:856 +msgid "" +"WARNING: Bad things are about to happen!\n" +"\n" +"The payment gateway used to purchase this subscription does not support " +"modifying a subscription's details.\n" +"\n" +"Changes to the billing period, recurring discount, recurring tax or " +"recurring total may not be reflected in the amount charged by the payment " +"gateway." +msgstr "" +"ATTENTION : De mauvaises choses sont sur le point d’arriver !\n" +"\n" +"La passerelle de paiement utilisée pour acheter cet abonnement ne prend pas " +"en charge la modification des détails d’un abonnement.\n" +"\n" +"Les modifications de la période de facturation, de la remise récurrente, des " +"taxes récurrentes ou du total récurrent peuvent ne pas être reflétées dans " +"le montant facturé par la passerelle de paiement." + +#: includes/admin/class-wc-subscriptions-admin.php:820 +msgid "" +"Trashing this order will also trash the subscriptions purchased with the " +"order." +msgstr "" +"Le déplacement de cette commande vers la corbeille entraînera également le " +"déplacement vers la corbeille des abonnements achetés avec la commande." + +#: includes/admin/class-wc-subscriptions-admin.php:843 +msgid "" +"You are about to trash one or more orders which contain a subscription.\n" +"\n" +"Trashing the orders will also trash the subscriptions purchased with these " +"orders." +msgstr "" +"Vous êtes sur le point de déplacer vers la corbeille une ou plusieurs " +"commandes contenant un abonnement.\n" +"\n" +"Le déplacement des commandes vers la corbeille entraînera également le " +"déplacement vers la corbeille des abonnements achetés avec ces commandes." + +#: includes/admin/class-wc-subscriptions-admin.php:835 +msgid "" +"Enter a new interval as a single number (e.g. to charge every 2nd month, " +"enter 2):" +msgstr "" +"Saisir un nouvel intervalle sous forme de nombre unique (par ex. pour " +"facturer tous les 2 mois, saisissez 2) :" + +#: includes/admin/class-wc-subscriptions-admin.php:834 +msgid "Enter a new length (e.g. 5):" +msgstr "Saisir une nouvelle durée (par ex. 5) :" + +#: includes/admin/class-wc-subscriptions-admin.php:833 +msgid "Enter the new period, either day, week, month or year:" +msgstr "Saisir la nouvelle période, soit jour, semaine, mois ou année :" + +#: includes/admin/class-wc-subscriptions-admin.php:453 +msgid "Free trial period" +msgstr "Période d’essai gratuit" + +#: includes/admin/class-wc-subscriptions-admin.php:452 +msgid "Free trial length" +msgstr "Durée de l’essai gratuit" + +#: includes/admin/class-wc-subscriptions-admin.php:312 +#: includes/admin/class-wc-subscriptions-admin.php:450 +msgid "Subscription period" +msgstr "Période d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:449 +msgid "Subscription billing interval" +msgstr "Intervalle de facturation de l’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:448 +msgid "Subscription sign-up fee" +msgstr "Frais d’inscription de l’abonnement" + +#: includes/upgrades/templates/wcs-about.php:115 +msgid "Subscription Gifting" +msgstr "Offre d’abonnement" + +#: includes/class-wcs-limiter.php:52 +msgid "Limit to one of any status" +msgstr "Limiter à un avec n’importe quel état" + +#: includes/class-wcs-limiter.php:51 +msgid "Limit to one active subscription" +msgstr "Limiter à un abonnement actif" + +#: includes/class-wcs-limiter.php:50 +msgid "Do not limit" +msgstr "Ne pas limiter" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wcs-limiter.php:48 +msgid "" +"Only allow a customer to have one subscription to this product. %1$sLearn " +"more%2$s." +msgstr "" +"Autorisez un client à n’avoir qu’un seul abonnement à ce produit. %1$sEn " +"savoir plus%2$s." + +#: includes/class-wcs-limiter.php:46 +msgid "Limit subscription" +msgstr "Limiter l’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:390 +msgid "" +"Shipping for subscription products is normally charged on the initial order " +"and all renewal orders. Enable this to only charge shipping once on the " +"initial order. Note: for this setting to be enabled the subscription must " +"not have a free trial or a synced renewal date." +msgstr "" +"La livraison des produits d’abonnement est normalement facturée sur la " +"commande initiale et toutes les commandes de renouvellement. Activez cette " +"option pour ne facturer les frais d’expédition qu’une seule fois sur la " +"commande initiale. Remarque : pour que ce paramètre soit activé, " +"l’abonnement ne doit pas avoir d’essai gratuit ni de date de renouvellement " +"synchronisée." + +#: includes/admin/class-wc-subscriptions-admin.php:389 +msgid "One time shipping" +msgstr "Livraison unique" + +#: includes/admin/class-wc-subscriptions-admin.php:357 +#: templates/admin/deprecated/html-variation-price.php:115 +msgid "Subscription Trial Period" +msgstr "Période d’essai d’abonnement" + +#: templates/admin/deprecated/html-variation-price.php:97 +#: templates/admin/deprecated/html-variation-price.php:104 +msgid "Free Trial" +msgstr "Essai gratuit" + +#: includes/admin/class-wc-subscriptions-admin.php:342 +msgid "" +"Optionally include an amount to be charged at the outset of the subscription." +" The sign-up fee will be charged immediately, even if the product has a free " +"trial or the payment dates are synced." +msgstr "" +"Incluez éventuellement un montant à facturer au début de l’abonnement. Les " +"frais d’inscription seront facturés immédiatement, même si le produit a un " +"essai gratuit ou si les dates de paiement sont synchronisées." + +#. translators: %s is a currency symbol / code +#. translators: placeholder is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:341 +#: templates/admin/deprecated/html-variation-price.php:31 +#: templates/admin/deprecated/html-variation-price.php:86 +#: templates/admin/html-variation-price.php:21 +#: templates/admin/html-variation-price.php:47 +msgctxt "example price" +msgid "e.g. 9.90" +msgstr "par ex. 9,90" + +#: templates/admin/deprecated/html-variation-price.php:85 +msgid "Sign-up Fee (%s)" +msgstr "Frais d’inscription (%s)" + +#: templates/admin/deprecated/html-variation-price.php:69 +msgid "Subscription Length" +msgstr "Durée de l’abonnement" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:34 +#: templates/admin/deprecated/html-variation-price.php:57 +msgid "Billing Period" +msgstr "Période de facturation" + +#: templates/admin/deprecated/html-variation-price.php:46 +msgid "Subscription Periods" +msgstr "Périodes d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:305 +msgctxt "example price" +msgid "e.g. 5.90" +msgstr "par ex. 5,90" + +#. translators: placeholder is a currency symbol / code +#: templates/admin/deprecated/html-variation-price.php:20 +#: templates/admin/deprecated/html-variation-price.php:30 +msgid "Subscription Price (%s)" +msgstr "Prix de l’abonnement (%s)" + +#: includes/admin/class-wc-subscriptions-admin.php:199 +msgid "Variable subscription" +msgstr "Abonnement variable" + +#: includes/admin/class-wc-subscriptions-admin.php:198 +msgid "Simple subscription" +msgstr "Abonnement simple" + +#. Plugin URI of the plugin +msgid "https://www.woocommerce.com/products/woocommerce-subscriptions/" +msgstr "https://www.woocommerce.com/products/woocommerce-subscriptions/" + +#. translators: billing period (e.g. "every week"). +#: includes/class-wc-subscriptions-product.php:377 +msgid "every %s" +msgstr "chaque %s" + +#: includes/admin/class-wc-subscriptions-admin.php:1320 +msgctxt "there's a number immediately in front of this text" +msgid "suspensions per billing period." +msgstr "suspensions par période de facturation." diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot index 6b76dd7..1aa6eb3 100644 --- a/languages/woocommerce-subscriptions.pot +++ b/languages/woocommerce-subscriptions.pot @@ -1,21 +1,21 @@ -# Copyright (C) 2020 WooCommerce +# Copyright (C) 2022 WooCommerce # This file is distributed under the same license as the WooCommerce Subscriptions plugin. msgid "" msgstr "" -"Project-Id-Version: WooCommerce Subscriptions 3.0.9\n" +"Project-Id-Version: WooCommerce Subscriptions 4.6.0\n" "Report-Msgid-Bugs-To: https://woocommerce.com/contact-us\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2020-09-29T04:57:17+00:00\n" +"POT-Creation-Date: 2022-10-11T04:47:59+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"X-Generator: WP-CLI 2.3.0\n" +"X-Generator: WP-CLI 2.6.0\n" "X-Domain: woocommerce-subscriptions\n" #. Plugin Name of the plugin -#: includes/privacy/class-wcs-privacy.php:40 +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:40 msgid "WooCommerce Subscriptions" msgstr "" @@ -28,8 +28,8 @@ msgid "Sell products and services with recurring payments in your WooCommerce St msgstr "" #. Author of the plugin -#: includes/admin/class-wcs-admin-reports.php:104 -#: includes/admin/reports/class-wcs-report-cache-manager.php:263 +#: includes/admin/class-wcs-admin-reports.php:101 +#: includes/admin/reports/class-wcs-report-cache-manager.php:262 msgid "WooCommerce" msgstr "" @@ -37,834 +37,22 @@ msgstr "" msgid "https://woocommerce.com/" msgstr "" -#. translators: 1: relation type, 2: list of valid relation types. -#: includes/abstracts/abstract-wcs-related-order-store.php:148 -msgid "Invalid relation type: %1$s. Order relationship type must be one of: %2$s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:198 -msgid "Simple subscription" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:199 -msgid "Variable subscription" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:220 -msgid "Downloadable" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:221 -msgid "Virtual" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:285 -msgid "Choose the subscription price, billing interval and period." -msgstr "" - -#. translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks") -#: includes/admin/class-wc-subscriptions-admin.php:287 -msgctxt "Trial period field tooltip on Edit Product administration screen" -msgid "An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s" -msgstr "" - -#. translators: %s: currency symbol. -#. translators: placeholder is a currency symbol / code -#: includes/admin/class-wc-subscriptions-admin.php:301 -#: templates/admin/html-variation-price.php:44 -msgid "Subscription price (%s)" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:305 -msgctxt "example price" -msgid "e.g. 5.90" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:306 -msgid "Subscription interval" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:312 -#: includes/admin/class-wc-subscriptions-admin.php:450 -msgid "Subscription period" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:327 -#: includes/admin/class-wc-subscriptions-admin.php:451 -#: templates/admin/html-variation-price.php:66 -msgid "Expire after" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:330 -msgid "Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date." -msgstr "" - -#. translators: %s is a currency symbol / code -#: includes/admin/class-wc-subscriptions-admin.php:340 -#: templates/admin/html-variation-price.php:20 -msgid "Sign-up fee (%s)" -msgstr "" - -#. translators: %s is a currency symbol / code -#. translators: placeholder is a currency symbol / code -#: includes/admin/class-wc-subscriptions-admin.php:341 -#: templates/admin/deprecated/html-variation-price.php:31 -#: templates/admin/deprecated/html-variation-price.php:86 -#: templates/admin/html-variation-price.php:21 -#: templates/admin/html-variation-price.php:47 -msgctxt "example price" -msgid "e.g. 9.90" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:342 -msgid "Optionally include an amount to be charged at the outset of the subscription. The sign-up fee will be charged immediately, even if the product has a free trial or the payment dates are synced." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:354 -#: templates/admin/html-variation-price.php:25 -msgid "Free trial" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:357 -#: templates/admin/deprecated/html-variation-price.php:115 -msgid "Subscription Trial Period" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:389 -msgid "One time shipping" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:390 -msgid "Shipping for subscription products is normally charged on the initial order and all renewal orders. Enable this to only charge shipping once on the initial order. Note: for this setting to be enabled the subscription must not have a free trial or a synced renewal date." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:447 -msgid "Subscription pricing" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:448 -msgid "Subscription sign-up fee" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:449 -msgid "Subscription billing interval" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:452 -msgid "Free trial length" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:453 -msgid "Free trial period" -msgstr "" - -#. translators: %s: subscription status. -#: includes/admin/class-wc-subscriptions-admin.php:778 -msgid "Unable to change subscription status to \"%s\". Please assign a customer to the subscription to activate it." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:820 -msgid "Trashing this order will also trash the subscriptions purchased with the order." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:833 -msgid "Enter the new period, either day, week, month or year:" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:834 -msgid "Enter a new length (e.g. 5):" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:835 -msgid "Enter a new interval as a single number (e.g. to charge every 2nd month, enter 2):" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:836 -msgid "Delete all variations without a subscription" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:843 -msgid "" -"You are about to trash one or more orders which contain a subscription.\n" -"\n" -"Trashing the orders will also trash the subscriptions purchased with these orders." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:856 -msgid "" -"WARNING: Bad things are about to happen!\n" -"\n" -"The payment gateway used to purchase this subscription does not support modifying a subscription's details.\n" -"\n" -"Changes to the billing period, recurring discount, recurring tax or recurring total may not be reflected in the amount charged by the payment gateway." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:857 -msgid "You are deleting a subscription item. You will also need to manually cancel and trash the subscription on the Manage Subscriptions screen." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:864 -msgid "" -"Warning: Deleting a user will also delete the user's subscriptions. The user's orders will remain but be reassigned to the 'Guest' user.\n" -"\n" -"Do you want to continue to delete this user and any associated subscriptions?" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:868 -msgid "PayPal Standard has a number of limitations and does not support all subscription features." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:868 -msgid "Because of this, it is not recommended as a payment method for Subscriptions unless it is the only available option for your country." -msgstr "" - -#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: "

    ", 3$: "

    ", 4$: "", 5$: "", 6$: "", 7$: "", 8$: "

    " -#: includes/admin/class-wc-subscriptions-admin.php:886 -msgctxt "used in admin pointer script params in javascript as type pointer content" -msgid "%1$sChoose Subscription%2$s%3$sThe WooCommerce Subscriptions extension adds two new subscription product types - %4$sSimple subscription%5$s and %6$sVariable subscription%7$s.%8$s" -msgstr "" - -#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: "

    ", 3$: "

    ", 4$: "

    " -#: includes/admin/class-wc-subscriptions-admin.php:888 -msgctxt "used in admin pointer script params in javascript as price pointer content" -msgid "%1$sSet a Price%2$s%3$sSubscription prices are a little different to other product prices. For a subscription, you can set a billing period, length, sign-up fee and free trial.%4$s" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:943 -msgid "Active subscriber?" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:986 -msgid "Manage Subscriptions" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:990 -#: woocommerce-subscriptions.php:272 -msgid "Search Subscriptions" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1012 -#: includes/admin/class-wc-subscriptions-admin.php:1164 #: includes/admin/class-wcs-admin-reports.php:46 -#: includes/admin/class-wcs-admin-system-status.php:56 -#: includes/admin/class-wcs-wc-admin-manager.php:35 #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:917 -#: includes/class-wcs-query.php:118 -#: includes/class-wcs-query.php:145 -#: includes/class-wcs-query.php:299 -#: includes/privacy/class-wcs-privacy-exporters.php:51 -#: woocommerce-subscriptions.php:263 -#: woocommerce-subscriptions.php:276 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1011 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1163 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:56 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:38 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:80 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:338 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:351 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:108 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:133 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:287 +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:51 msgid "Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1204 -msgid "Button Text" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1211 -msgid "Add to Cart Button Text" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1212 -msgid "A product displays a button with the text \"Add to cart\". By default, a subscription changes this to \"Sign up now\". You can customise the button text for subscriptions here." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1216 -#: includes/admin/class-wc-subscriptions-admin.php:1219 -#: includes/admin/class-wc-subscriptions-admin.php:1228 -#: includes/admin/class-wc-subscriptions-admin.php:1231 -#: includes/class-wc-product-subscription-variation.php:98 -#: includes/class-wc-product-variable-subscription.php:73 -#: includes/class-wc-subscriptions-product.php:1192 -#: includes/class-wc-subscriptions-product.php:1210 -#: woocommerce-subscriptions.php:603 -msgid "Sign up now" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1223 -msgid "Place Order Button Text" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1224 -msgid "Use this field to customise the text displayed on the checkout button when an order contains a subscription. Normally the checkout submission button displays \"Place order\". When the cart contains a subscription, this is changed to \"Sign up now\"." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1240 -msgid "Roles" -msgstr "" - -#. translators: placeholders are tags -#: includes/admin/class-wc-subscriptions-admin.php:1243 -msgid "Choose the default roles to assign to active and inactive subscribers. For record keeping purposes, a user account must be created for subscribers. Users with the %1$sadministrator%2$s role, such as yourself, will never be allocated these roles to prevent locking out administrators." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1248 -msgid "Subscriber Default Role" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1249 -msgid "When a subscription is activated, either manually or after a successful purchase, new users will be assigned this role." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1260 -msgid "Inactive Subscriber Role" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1261 -msgid "If a subscriber's subscription is manually cancelled or expires, she will be assigned this role." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1277 -msgctxt "option section heading" -msgid "Renewals" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1284 -msgid "Manual Renewal Payments" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1285 -msgid "Accept Manual Renewals" -msgstr "" - -#. translators: placeholders are opening and closing link tags -#: includes/admin/class-wc-subscriptions-admin.php:1290 -msgid "With manual renewals, a customer's subscription is put on-hold until they login and pay to renew it. %1$sLearn more%2$s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1296 -msgid "Turn off Automatic Payments" -msgstr "" - -#. translators: placeholders are opening and closing link tags -#: includes/admin/class-wc-subscriptions-admin.php:1301 -msgid "If you don't want new subscription purchases to automatically charge renewal payments, you can turn off automatic payments. Existing automatic subscriptions will continue to charge customers automatically. %1$sLearn more%2$s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1312 -msgctxt "options section heading" -msgid "Miscellaneous" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1319 -msgid "Customer Suspensions" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1320 -msgctxt "there's a number immediately in front of this text" -msgid "suspensions per billing period." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1326 -msgid "Set a maximum number of times a customer can suspend their account for each billing period. For example, for a value of 3 and a subscription billed yearly, if the customer has suspended their account 3 times, they will not be presented with the option to suspend their account until the next year. Store managers will always be able to suspend an active subscription. Set this to 0 to turn off the customer suspension feature completely." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1330 -msgid "Mixed Checkout" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1331 -msgid "Allow multiple subscriptions and products to be purchased simultaneously." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1335 -msgid "Allow a subscription product to be purchased with other products and subscriptions in the same transaction." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1339 -msgid "$0 Initial Checkout" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1340 -msgid "Allow $0 initial checkout without a payment method." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1344 -msgid "Allow a subscription product with a $0 initial payment to be purchased without providing a payment method. The customer will be required to provide a payment method at the end of the initial period to keep the subscription active." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1348 -#: includes/upgrades/templates/wcs-about-2-0.php:108 -msgid "Drip Downloadable Content" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1349 -msgid "Enable dripping for downloadable content on subscription products." -msgstr "" - -#. translators: %s is a line break. -#: includes/admin/class-wc-subscriptions-admin.php:1354 -msgid "Enabling this grants access to new downloadable files added to a product only after the next renewal is processed.%sBy default, access to new downloadable files added to a product is granted immediately to any customer that has an active subscription with that product." -msgstr "" - -#. translators: $1-$2: opening and closing tags, $3-$4: opening and closing tags -#: includes/admin/class-wc-subscriptions-admin.php:1395 -msgid "%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou're ready to start selling subscriptions!%4$s" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1413 -msgid "Add a Subscription Product" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1414 -#: includes/upgrades/templates/wcs-about-2-0.php:35 -#: includes/upgrades/templates/wcs-about.php:34 -#: woocommerce-subscriptions.php:1145 -msgid "Settings" -msgstr "" - -#. translators: placeholder is a number -#: includes/admin/class-wc-subscriptions-admin.php:1497 -msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" -msgstr "" - -#. translators: Placeholders are opening and closing link tags. -#: includes/admin/class-wc-subscriptions-admin.php:1541 -msgid "We weren't able to locate the set of report results you requested. Please regenerate the link from the %1$sSubscription Reports screen%2$s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1595 -msgid "We can't find a paid subscription order for this user." -msgstr "" - -#. translators: placeholders are opening link tag, ID of sub, and closing link tag -#: includes/admin/class-wc-subscriptions-admin.php:1627 -#: includes/admin/class-wc-subscriptions-admin.php:1632 -msgid "Showing orders for %1$sSubscription %2$s%3$s" -msgstr "" - -#. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years -#: includes/admin/class-wc-subscriptions-admin.php:1656 -msgid "The trial period can not exceed: %1$s, %2$s, %3$s or %4$s." -msgstr "" - -#. translators: placeholder is a time period (e.g. "4 weeks") -#: includes/admin/class-wc-subscriptions-admin.php:1661 -msgid "The trial period can not exceed %s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1723 -#: includes/admin/class-wcs-admin-system-status.php:93 -msgctxt "label that indicates whether debugging is turned on for the plugin" -msgid "WCS_DEBUG" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1724 -#: includes/admin/class-wc-subscriptions-admin.php:1791 -#: includes/admin/class-wcs-admin-system-status.php:95 -#: includes/admin/reports/class-wcs-report-cache-manager.php:317 -msgid "Yes" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1724 -#: includes/admin/class-wcs-admin-system-status.php:95 -#: includes/admin/reports/class-wcs-report-cache-manager.php:317 -msgid "No" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1729 -#: includes/admin/class-wcs-admin-system-status.php:107 -msgctxt "Live or Staging, Label on WooCommerce -> System Status page" -msgid "Subscriptions Mode" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1730 -#: includes/admin/class-wcs-admin-system-status.php:109 -msgctxt "refers to staging site" -msgid "Staging" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1730 -#: includes/admin/class-wcs-admin-system-status.php:109 -msgctxt "refers to live site" -msgid "Live" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1760 -msgid "Automatic Recurring Payments" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1791 -msgid "Supports automatic renewal payments with the WooCommerce Subscriptions extension." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1889 -msgid "Subscription items can no longer be edited." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1893 -msgid "This subscription is no longer editable because the payment gateway does not allow modification of recurring amounts." -msgstr "" - -#. translators: $1-2: opening and closing tags of a link that takes to Woo marketplace / Stripe product page -#: includes/admin/class-wc-subscriptions-admin.php:1912 -msgid "No payment gateways capable of processing automatic subscription payments are enabled. If you would like to process automatic payments, we recommend the %1$sfree Stripe extension%2$s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1917 -msgid "Recurring Payments" -msgstr "" - -#. translators: placeholders are opening and closing link tags -#: includes/admin/class-wc-subscriptions-admin.php:1925 -msgid "Payment gateways which don't support automatic recurring payments can be used to process %1$smanual subscription renewal payments%2$s." -msgstr "" - -#. translators: $1-$2: opening and closing tags. Link to documents->payment gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions shop page -#: includes/admin/class-wc-subscriptions-admin.php:1932 -msgid "Find new gateways that %1$ssupport automatic subscription payments%2$s in the official %3$sWooCommerce Marketplace%4$s." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:2036 -msgid "Note that purchasing a subscription still requires an account." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:2050 -msgid "The product type can not be changed because this product is associated with subscriptions." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:62 -msgctxt "meta box title" -msgid "Subscription Data" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:64 -msgctxt "meta box title" -msgid "Schedule" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:68 -#: includes/admin/class-wcs-admin-meta-boxes.php:72 -msgid "Related Orders" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:112 -msgid "Please enter a start date in the past." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:113 -msgid "Please enter a date at least one hour into the future." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:114 -msgid "Please enter a date after the trial end." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:115 -#: includes/admin/class-wcs-admin-meta-boxes.php:116 -msgid "Please enter a date after the start date." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:117 -msgid "Please enter a date before the next payment." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:118 -msgid "Please enter a date after the next payment." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:119 -msgid "" -"Are you sure you want to process a renewal?\n" -"\n" -"This will charge the customer and email them the renewal order (if emails are enabled)." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:132 -msgid "" -"Are you sure you want to retry payment for this renewal order?\n" -"\n" -"This will attempt to charge the customer and send renewal order emails (if emails are enabled)." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:165 -msgid "Process renewal" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:169 -msgid "Create pending renewal order" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:171 -msgid "Create pending parent order" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:175 -msgid "Retry Renewal Payment" -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:188 -msgid "Process renewal order action requested by admin." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:199 -msgid "Create pending renewal order requested by admin action." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:241 -msgid "Create pending parent order requested by admin action." -msgstr "" - -#: includes/admin/class-wcs-admin-meta-boxes.php:272 -msgid "Retry renewal payment action requested by admin." -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:214 -msgid "Search for a product…" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:258 -msgctxt "an action on a subscription" -msgid "Activate" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:259 -msgctxt "an action on a subscription" -msgid "Put on-hold" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:260 -#: includes/admin/class-wcs-admin-post-types.php:473 -#: includes/class-wc-subscriptions-manager.php:1839 -#: includes/wcs-user-functions.php:354 -#: templates/myaccount/related-orders.php:78 -msgctxt "an action on a subscription" -msgid "Cancel" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:335 -msgctxt "Used in order note. Reason why status changed." -msgid "Subscription status changed by bulk edit:" -msgstr "" - -#. translators: placeholder is the number of subscriptions updated -#: includes/admin/class-wcs-admin-post-types.php:391 -msgid "%s subscription status changed." -msgid_plural "%s subscription statuses changed." -msgstr[0] "" -msgstr[1] "" - -#. translators: 1$: is the number of subscriptions not updated, 2$: is the error message -#: includes/admin/class-wcs-admin-post-types.php:398 -msgid "%1$s subscription could not be updated: %2$s" -msgid_plural "%1$s subscriptions could not be updated: %2$s" -msgstr[0] "" -msgstr[1] "" - -#: includes/admin/class-wcs-admin-post-types.php:422 -#: includes/admin/meta-boxes/views/html-related-orders-table.php:20 -#: templates/myaccount/my-subscriptions.php:22 -#: templates/myaccount/my-subscriptions.php:37 -#: templates/myaccount/related-orders.php:24 -#: templates/myaccount/related-orders.php:50 -#: templates/myaccount/related-subscriptions.php:22 -#: templates/myaccount/related-subscriptions.php:36 -#: templates/myaccount/subscription-details.php:18 -msgid "Status" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:423 -#: templates/emails/cancelled-subscription.php:21 -#: templates/emails/expired-subscription.php:21 -#: templates/emails/on-hold-subscription.php:21 -#: templates/myaccount/my-subscriptions.php:21 -#: templates/myaccount/related-subscriptions.php:21 -#: woocommerce-subscriptions.php:264 -msgid "Subscription" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:424 -msgid "Items" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:425 -msgid "Total" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:426 -msgid "Start Date" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:427 -msgid "Trial End" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:428 -msgid "Next Payment" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:429 -msgid "Last Order Date" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:430 -msgid "End Date" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:431 -msgctxt "number of orders linked to a subscription" -msgid "Orders" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:471 -#: includes/wcs-user-functions.php:338 -msgid "Reactivate" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:472 -#: includes/wcs-user-functions.php:333 -msgid "Suspend" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:474 -#: includes/admin/class-wcs-admin-post-types.php:489 -msgid "Trash" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:475 -#: includes/admin/class-wcs-admin-post-types.php:493 -msgid "Delete Permanently" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:487 -#: includes/class-wc-subscriptions-product.php:762 -msgid "Restore this item from the Trash" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:487 -#: includes/class-wc-subscriptions-product.php:763 -msgid "Restore" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:489 -msgid "Move this item to the Trash" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:493 -msgid "Delete this item permanently" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:499 -msgid "Cancel Now" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:527 -msgctxt "meaning billing address" -msgid "Billing:" -msgstr "" - -#. translators: placeholder is customer's billing email -#: includes/admin/class-wcs-admin-post-types.php:532 -msgid "Email: %s" -msgstr "" - -#. translators: placeholder is customer's billing phone number -#: includes/admin/class-wcs-admin-post-types.php:537 -msgid "Tel: %s" -msgstr "" - -#. translators: $1: is opening link, $2: is subscription order number, $3: is closing link tag, $4: is user's name -#: includes/admin/class-wcs-admin-post-types.php:565 -msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)" -msgid "%1$s#%2$s%3$s for %4$s" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:569 -msgid "Show more details" -msgstr "" - -#. translators: %d: item count. -#: includes/admin/class-wcs-admin-post-types.php:590 -msgid "%d item" -msgid_plural "%d items" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is the display name of a payment gateway a subscription was paid by -#. translators: %s: payment method. -#: includes/admin/class-wcs-admin-post-types.php:609 -#: includes/class-wc-subscription.php:2017 -msgid "Via %s" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:651 -msgid "Y/m/d g:i:s A" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:654 -msgid "This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed." -msgstr "" - -#. translators: placeholder is previous post title -#: includes/admin/class-wcs-admin-post-types.php:907 -#: includes/admin/class-wcs-admin-post-types.php:910 -#: includes/admin/class-wcs-admin-post-types.php:913 -msgid "Subscription updated." -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:908 -msgid "Custom field updated." -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:909 -msgid "Custom field deleted." -msgstr "" - -#. translators: placeholder is previous post title -#: includes/admin/class-wcs-admin-post-types.php:912 -msgctxt "used in post updated messages" -msgid "Subscription restored to revision from %s" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:914 -msgid "Subscription saved." -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:915 -msgid "Subscription submitted." -msgstr "" - -#. translators: php date string -#: includes/admin/class-wcs-admin-post-types.php:917 -msgid "Subscription scheduled for: %1$s." -msgstr "" - -#. translators: php date string -#: includes/admin/class-wcs-admin-post-types.php:917 -msgctxt "used in \"Subscription scheduled for \"" -msgid "M j, Y @ G:i" -msgstr "" - -#. translators: php date string -#: includes/admin/class-wcs-admin-post-types.php:918 -msgid "Subscription draft updated." -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:954 -msgid "Any Payment Method" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:955 -msgid "None" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:961 -#: includes/class-wc-subscription.php:1999 -#: includes/class-wcs-change-payment-method-admin.php:168 -msgid "Manual Renewal" -msgstr "" - -#. translators: 1: user display name 2: user ID 3: user email -#: includes/admin/class-wcs-admin-post-types.php:1107 -msgid "%1$s (#%2$s – %3$s)" -msgstr "" - -#: includes/admin/class-wcs-admin-post-types.php:1114 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:85 -msgid "Search for a customer…" -msgstr "" - #: includes/admin/class-wcs-admin-reports.php:49 msgid "Subscription Events by Date" msgstr "" @@ -889,411 +77,65 @@ msgstr "" msgid "Failed Payment Retries" msgstr "" -#: includes/admin/class-wcs-admin-system-status.php:57 -msgid "This section shows any information about Subscriptions." -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:61 -msgid "Store Setup" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:62 -msgid "This section shows general information about the store." -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:66 -msgid "Subscriptions by Payment Gateway" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:67 -msgid "This section shows information about Subscription payment methods." -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:71 -msgid "Payment Gateway Support" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:72 -msgid "This section shows information about payment gateway feature support." -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:119 -msgctxt "Live URL, Label on WooCommerce -> System Status page" -msgid "Subscriptions Live URL" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:135 -msgctxt "label for the system status page" -msgid "Subscriptions Template Theme Overrides" -msgstr "" - -#. translators: placeholders are opening/closing tags linking to documentation on outdated templates. -#: includes/admin/class-wcs-admin-system-status.php:145 -msgid "%1$sLearn how to update%2$s" -msgstr "" - -#. translators: %1$s is the file version, %2$s is the core version -#: includes/admin/class-wcs-admin-system-status.php:191 -msgid "version %1$s is out of date. The core version is %2$s" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:221 -msgctxt "label for the system status page" -msgid "Subscription Statuses" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:242 -msgctxt "label for the system status page" -msgid "WooCommerce Account Connected" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:265 -msgctxt "label for the system status page" -msgid "Active Product Key" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:295 -msgctxt "label for the system status page" -msgid "Other" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:329 -msgctxt "label for the system status page" -msgid "PayPal Reference Transactions Enabled" -msgstr "" - -#: includes/admin/class-wcs-admin-system-status.php:357 -msgctxt "label for the system status page" -msgid "Country / State" -msgstr "" - -#: includes/admin/class-wcs-wc-admin-manager.php:46 -msgid "Add New" -msgstr "" - -#: includes/admin/class-wcs-wc-admin-manager.php:56 -msgid "Edit Subscription" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:77 -msgctxt "relation to order" -msgid "Subscription" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:82 -msgctxt "relation to order" -msgid "Initial Subscription" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:93 -msgctxt "relation to order" -msgid "Renewal Order" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:96 -msgctxt "relation to order" -msgid "Parent Order" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 -msgctxt "relation to order" -msgid "Resubscribed Subscription" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 -msgctxt "relation to order" -msgid "Resubscribe Order" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:102 -msgctxt "relation to order" -msgid "Unknown Order Type" -msgstr "" - -#. translators: placeholder is the ID of the subscription -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:48 -msgctxt "edit subscription header" -msgid "Subscription #%s details" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:52 -msgid "General" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:55 -msgid "Customer:" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:64 -msgid "View other subscriptions →" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:69 -msgid "Profile →" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:93 -msgid "Subscription status:" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:110 -msgid "Parent order: " -msgstr "" - -#. translators: placeholder is an order number. -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:114 -msgid "#%1$s" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:121 -msgid "Parent order:" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:127 -msgid "Select an order…" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 -msgid "Billing" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:138 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:229 -#: includes/payment-retry/class-wcs-retry-post-store.php:40 -msgid "Edit" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:140 -msgid "Load billing address" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:148 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:240 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 -msgid "Address" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 -msgid "No billing address set." -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:170 -#: includes/class-wcs-change-payment-method-admin.php:38 -#: includes/class-wcs-change-payment-method-admin.php:51 -msgid "Payment Method" -msgstr "" - -#. translators: %s: gateway ID. -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:175 -#: includes/class-wcs-change-payment-method-admin.php:53 -msgctxt "The gateway ID displayed on the Edit Subscriptions screen when editing payment method." -msgid "Gateway ID: [%s]" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:212 -msgid "Customer change payment method page →" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:214 -msgid "Customer add payment method page →" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:228 -msgid "Shipping" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:231 -msgid "Load shipping address" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:232 -msgid "Copy billing address" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 -msgid "No shipping address set." -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:264 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:294 -msgid "Customer Provided Note" -msgstr "" - -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:295 -msgid "Customer's notes about the order" -msgstr "" - -#. translators: %s: parent order number (linked to its details screen). -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:387 -msgctxt "subscription note after linking to a parent order" -msgid "Subscription linked to parent order %s via admin." -msgstr "" - -#. translators: placeholder is error message from the payment gateway or subscriptions when updating the status -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:401 -msgid "Error updating some information: %s" -msgstr "" - -#. translators: placeholder is an order number. -#. translators: placeholder is an order ID. -#. translators: %s: order number. -#. translators: %s: order ID. -#: includes/admin/meta-boxes/views/html-related-orders-row.php:21 -#: includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:18 -#: includes/class-wc-subscriptions-renewal-order.php:158 -#: includes/early-renewal/class-wcs-cart-early-renewal.php:309 -#: includes/early-renewal/wcs-early-renewal-functions.php:162 -#: templates/myaccount/my-subscriptions.php:34 -#: templates/myaccount/related-orders.php:44 -#: templates/myaccount/related-subscriptions.php:33 -msgctxt "hash before order number" -msgid "#%s" -msgstr "" - -#. translators: php date format -#: includes/admin/meta-boxes/views/html-related-orders-row.php:33 -#: includes/admin/meta-boxes/views/html-retries-table.php:44 -msgctxt "post date" -msgid "Y/m/d g:i:s A" -msgstr "" - -#: includes/admin/meta-boxes/views/html-related-orders-row.php:36 -#: includes/admin/meta-boxes/views/html-retries-table.php:47 -msgid "Unpublished" -msgstr "" - -#: includes/admin/meta-boxes/views/html-related-orders-table.php:17 -#: templates/myaccount/related-orders.php:42 -msgid "Order Number" -msgstr "" - -#: includes/admin/meta-boxes/views/html-related-orders-table.php:18 -msgid "Relationship" -msgstr "" - -#: includes/admin/meta-boxes/views/html-related-orders-table.php:19 -#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:776 -#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:195 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:209 -#: templates/myaccount/related-orders.php:23 -#: templates/myaccount/related-orders.php:47 -msgid "Date" -msgstr "" - -#: includes/admin/meta-boxes/views/html-related-orders-table.php:21 -#: templates/myaccount/my-subscriptions.php:24 -#: templates/myaccount/related-orders.php:25 -#: templates/myaccount/related-subscriptions.php:24 -#: templates/myaccount/subscription-totals-table.php:22 -msgctxt "table heading" -msgid "Total" -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:17 -msgid "Retry Date" -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:19 -msgid "Retry Status" -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:20 -msgid "The status of the automatic payment retry: pending means the retry will be processed in the future, failed means the payment was not successful when retried and completed means the payment succeeded when retried." -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:23 -msgid "Status of Order" -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:24 -msgid "The status applied to the order for the time between when the renewal payment failed or last retry occurred and when this retry was processed." -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:27 -msgid "Status of Subscription" -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:28 -msgid "The status applied to the subscription for the time between when the renewal payment failed or last retry occurred and when this retry was processed." -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:31 -msgid "Email" -msgstr "" - -#: includes/admin/meta-boxes/views/html-retries-table.php:32 -msgid "The email sent to the customer when the renewal payment or payment retry failed to notify them that the payment would be retried." -msgstr "" - -#: includes/admin/meta-boxes/views/html-subscription-schedule.php:23 -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:72 -msgid "Payment:" -msgstr "" - -#: includes/admin/meta-boxes/views/html-subscription-schedule.php:34 -#: templates/admin/deprecated/html-variation-price.php:57 -msgid "Billing Period" -msgstr "" - -#: includes/admin/meta-boxes/views/html-subscription-schedule.php:43 -msgid "Recurring:" -msgstr "" - -#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 -msgid "Timezone:" -msgstr "" - -#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 -msgid "Error: unable to find timezone of your browser." -msgstr "" - -#: includes/admin/reports/class-wcs-report-cache-manager.php:266 +#: includes/admin/reports/class-wcs-report-cache-manager.php:265 msgid "Please note: data for this report is cached. The data displayed may be out of date by up to 24 hours. The cache is updated each morning at 4am in your site's timezone." msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:315 +#: includes/admin/reports/class-wcs-report-cache-manager.php:314 msgctxt "Whether the Report Cache has been enabled" msgid "Report Cache Enabled" msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:321 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1549 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1618 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:95 +msgid "Yes" +msgstr "" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1549 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:95 +msgid "No" +msgstr "" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:320 msgid "Cache Update Failures" msgstr "" #. translators: %d refers to the number of times we have detected cache update failures -#: includes/admin/reports/class-wcs-report-cache-manager.php:324 +#: includes/admin/reports/class-wcs-report-cache-manager.php:323 msgid "%d failures" msgid_plural "%d failure" msgstr[0] "" msgstr[1] "" #. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, respectively. -#: includes/admin/reports/class-wcs-report-dashboard.php:212 +#: includes/admin/reports/class-wcs-report-dashboard.php:216 msgid "%2$s%1$s signup%3$s subscription signups this month" msgid_plural "%2$s%1$s signups%3$s subscription signups this month" msgstr[0] "" msgstr[1] "" #. translators: %s: formatted amount. -#: includes/admin/reports/class-wcs-report-dashboard.php:220 +#: includes/admin/reports/class-wcs-report-dashboard.php:224 msgid "%s signup revenue this month" msgstr "" #. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, respectively. -#: includes/admin/reports/class-wcs-report-dashboard.php:228 +#: includes/admin/reports/class-wcs-report-dashboard.php:232 msgid "%2$s%1$s renewal%3$s subscription renewals this month" msgid_plural "%2$s%1$s renewals%3$s subscription renewals this month" msgstr[0] "" msgstr[1] "" #. translators: %s: formatted amount. -#: includes/admin/reports/class-wcs-report-dashboard.php:236 +#: includes/admin/reports/class-wcs-report-dashboard.php:240 msgid "%s renewal revenue this month" msgstr "" #. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, respectively. -#: includes/admin/reports/class-wcs-report-dashboard.php:244 +#: includes/admin/reports/class-wcs-report-dashboard.php:248 msgid "%2$s%1$s cancellation%3$s subscription cancellations this month" msgid_plural "%2$s%1$s cancellations%3$s subscription cancellations this month" msgstr[0] "" @@ -1471,7 +313,6 @@ msgstr "" msgid "%s signup revenue in this period" msgstr "" -#. translators: %s: formatted total amount. #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:489 msgid "The sum of all subscription parent orders, including other items, fees, tax and shipping." msgstr "" @@ -1481,7 +322,6 @@ msgstr "" msgid "%s renewal revenue in this period" msgstr "" -#. translators: %s: formatted total amount. #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:497 msgid "The sum of all renewal orders including tax and shipping." msgstr "" @@ -1491,7 +331,6 @@ msgstr "" msgid "%s resubscribe revenue in this period" msgstr "" -#. translators: %s: formatted total amount. #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:505 msgid "The sum of all resubscribe orders including tax and shipping." msgstr "" @@ -1501,7 +340,6 @@ msgstr "" msgid "%s switch revenue in this period" msgstr "" -#. translators: %s: formatted total amount. #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:513 msgid "The sum of all switch orders including tax and shipping." msgstr "" @@ -1612,6 +450,15 @@ msgstr "" msgid "Last 7 Days" msgstr "" +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:776 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:195 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:209 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php:19 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:23 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:47 +msgid "Date" +msgstr "" + #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:780 #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:199 #: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:213 @@ -1667,7 +514,6 @@ msgstr "" msgid "%s renewal revenue recovered" msgstr "" -#. translators: %s: formatted amount. #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:114 msgid "The total amount of revenue, including tax and shipping, recovered with the failed payment retry system for renewal orders with a failed payment." msgstr "" @@ -1678,7 +524,6 @@ msgstr "" msgid "%s renewal orders" msgstr "" -#. translators: %s: renewal count. #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:122 msgid "The number of renewal orders which had a failed payment use the retry system." msgstr "" @@ -1688,7 +533,6 @@ msgstr "" msgid "%s retry attempts succeeded" msgstr "" -#. translators: %s: retry count. #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:129 msgid "The number of renewal payment retries for this period which were able to process the payment which had previously failed one or more times." msgstr "" @@ -1698,7 +542,6 @@ msgstr "" msgid "%s retry attempts failed" msgstr "" -#. translators: %s: retry count. #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:137 msgid "The number of renewal payment retries for this period which did not result in a successful payment." msgstr "" @@ -1708,7 +551,6 @@ msgstr "" msgid "%s retry attempts pending" msgstr "" -#. translators: %s: retry count. #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:145 msgid "The number of renewal payment retries not yet processed." msgstr "" @@ -1734,12 +576,10 @@ msgstr "" msgid "%s renewal income in this period" msgstr "" -#. translators: %s: formatted amount. #: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:90 msgid "The sum of all the upcoming renewal orders, including items, fees, tax and shipping, for currently active subscriptions." msgstr "" -#. translators: %s: renewal count. #: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:97 msgid "The number of upcoming renewal orders, for currently active subscriptions." msgstr "" @@ -1773,180 +613,167 @@ msgstr "" msgid "Renewals amount" msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:184 -msgid "Customer ID is invalid." +#: includes/api/class-wc-rest-subscription-system-status-manager.php:34 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:56 +msgid "staging" msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:289 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:172 -msgid "Invalid subscription id." +#: includes/api/class-wc-rest-subscription-system-status-manager.php:34 +msgid "live" msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:360 -#: includes/api/legacy/class-wc-api-subscriptions.php:315 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:306 -msgid "Gateway does not support admin changing the payment method on a Subscription." +#: includes/api/class-wc-rest-subscription-system-status-manager.php:79 +msgid "Subscriptions." msgstr "" -#. translators: 1$: gateway id, 2$: error message -#: includes/api/class-wc-rest-subscriptions-controller.php:398 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336 -msgid "Subscription payment method could not be set to %1$s with error message: %2$s" +#: includes/api/class-wc-rest-subscription-system-status-manager.php:85 +msgid "WCS debug constant." msgstr "" -#. translators: placeholder is an error message. -#: includes/api/class-wc-rest-subscriptions-controller.php:468 -#: includes/api/class-wc-rest-subscriptions-controller.php:774 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:287 -msgid "Updating subscription dates errored with message: %s" +#: includes/api/class-wc-rest-subscription-system-status-manager.php:91 +msgid "Subscriptions Mode" msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:493 -msgid "The status to transition the subscription to. Unlike the \"status\" param, this will calculate and update the subscription dates." +#: includes/api/class-wc-rest-subscription-system-status-manager.php:97 +msgid "Subscriptions Live Site URL" msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:499 +#: includes/api/class-wc-rest-subscription-system-status-manager.php:104 +msgid "Subscriptions broken down by status." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:113 +msgid "Whether the Report Cache is enabled." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:119 +msgid "Number of report cache failures." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:125 +msgid "Subscriptions by Payment Gateway." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:134 +msgid "Payment Gateway Feature Support." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:155 +msgid "Invalid subscription ID." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:161 +msgid "Failed to load subscription object with the ID %d." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:323 +msgid "Subscription dates could not be set. Error message: %s" +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:359 +msgid "Subscription status." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:362 +msgid "Where the subscription was created." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:363 +msgid "Currency the subscription was created with, in ISO format." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:364 +msgid "The date the subscription was created, in the site's timezone." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:365 +msgid "The date the subscription was created, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:366 +msgid "The date the subscription was last modified, in the site's timezone." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:367 +msgid "The date the subscription was last modified, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:368 +msgid "User ID who owns the subscription." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:378 +msgid "The status to transition a subscription to." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:384 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:350 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:508 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:175 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:449 msgid "The number of billing periods between subscription renewals." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:504 +#: includes/api/class-wc-rest-subscriptions-controller.php:389 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:355 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:513 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:168 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:442 msgid "Billing period for the subscription." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:510 +#: includes/api/class-wc-rest-subscriptions-controller.php:395 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:361 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:519 msgid "Subscription payment details." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:515 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:366 -msgid "Payment gateway ID." +#: includes/api/class-wc-rest-subscriptions-controller.php:400 +msgid "Payment method meta and token in a post_meta_key: token format." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:522 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:373 -msgid "The subscription's start date." +#: includes/api/class-wc-rest-subscriptions-controller.php:405 +msgid "Payment method meta and token in a user_meta_key : token format." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:527 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:378 -msgid "The subscription's trial date" +#: includes/api/class-wc-rest-subscriptions-controller.php:412 +msgid "The subscription's start date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:532 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:383 -msgid "The subscription's next payment date." +#: includes/api/class-wc-rest-subscriptions-controller.php:417 +msgid "The subscription's trial date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:537 -#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:388 -msgid "The subscription's end date." +#: includes/api/class-wc-rest-subscriptions-controller.php:422 +msgid "The subscription's next payment date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:542 -msgid "The subscription's original subscription ID if this is a resubscribed subscription." +#: includes/api/class-wc-rest-subscriptions-controller.php:427 +msgid "The subscription's cancelled date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:548 -msgid "The subscription's resubscribed subscription ID." +#: includes/api/class-wc-rest-subscriptions-controller.php:432 +msgid "The subscription's end date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:554 -msgid "The date the subscription's latest order was completed, in GMT." +#: includes/api/class-wc-rest-subscriptions-controller.php:451 +msgid "Limit result set to subscriptions which have specific statuses." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:560 -msgid "The date the subscription's latest order was paid, in GMT." +#. translators: placeholder is the payment method ID. +#: includes/api/class-wc-rest-subscriptions-controller.php:495 +msgid "The %s payment gateway does not support admin changing the payment method." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:566 -msgid "Removed line items data." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:573 -msgid "Item ID." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:579 -msgid "Product name." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:585 -msgid "Product SKU." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:591 -msgid "Product ID." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:596 -msgid "Variation ID, if applicable." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:601 -msgid "Quantity ordered." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:606 -msgid "Tax class of product." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:612 -msgid "Product price." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:618 -msgid "Line subtotal (before discounts)." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:623 -msgid "Line subtotal tax (before discounts)." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:628 -msgid "Line total (after discounts)." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:633 -msgid "Line total tax (after discounts)." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:638 -msgid "Line taxes." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:646 -msgid "Tax rate ID." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:652 -msgid "Tax total." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:658 -msgid "Tax subtotal." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:667 -msgid "Removed line item meta data." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:675 -msgid "Meta key." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:681 -msgid "Meta label." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:687 -msgid "Meta value." +#. translators: 1$: gateway id, 2$: error message +#: includes/api/class-wc-rest-subscriptions-controller.php:512 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:407 +msgid "Subscription payment method could not be set to %1$s with error message: %2$s" msgstr "" #: includes/api/legacy/class-wc-api-subscriptions.php:102 -#: wcs-functions.php:178 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:175 msgid "Invalid subscription status given." msgstr "" @@ -1968,1083 +795,206 @@ msgctxt "API error message when editing the order failed" msgid "Edit subscription failed with error: %s" msgstr "" +#: includes/api/legacy/class-wc-api-subscriptions.php:314 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:306 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:369 +msgid "Gateway does not support admin changing the payment method on a Subscription." +msgstr "" + #. translators: 1$: gateway id, 2$: error message -#: includes/api/legacy/class-wc-api-subscriptions.php:353 +#: includes/api/legacy/class-wc-api-subscriptions.php:352 msgid "Subscription payment method could not be set to %1$s and has been set to manual with error message: %2$s" msgstr "" -#: includes/api/legacy/class-wc-api-subscriptions.php:388 -#: wcs-functions.php:152 +#: includes/api/legacy/class-wc-api-subscriptions.php:387 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:149 msgid "Invalid subscription billing interval given. Must be an integer greater than 0." msgstr "" -#: includes/api/legacy/class-wc-api-subscriptions.php:399 -#: wcs-functions.php:147 +#: includes/api/legacy/class-wc-api-subscriptions.php:398 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:144 msgid "Invalid subscription billing period given." msgstr "" -#: includes/api/legacy/class-wc-api-subscriptions.php:614 +#: includes/api/legacy/class-wc-api-subscriptions.php:613 msgctxt "API response confirming order note deleted from a subscription" msgid "Permanently deleted subscription note" msgstr "" +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:172 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:294 +msgid "Invalid subscription id." +msgstr "" + #. translators: placeholder is an error message. #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:242 msgid "Cannot create subscription: %s." msgstr "" -#: includes/class-wc-product-subscription.php:73 -msgid "Read more" +#. translators: placeholder is an error message. +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:287 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:477 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:783 +msgid "Updating subscription dates errored with message: %s" msgstr "" -#. translators: %s: subscription status. -#: includes/class-wc-subscription.php:415 -msgid "Unable to change subscription status to \"%s\"." +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:366 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:524 +msgid "Payment gateway ID." msgstr "" -#. translators: 1: subscription status, 2: error message. -#: includes/class-wc-subscription.php:538 -msgid "Unable to change subscription status to \"%1$s\". Exception: %2$s" +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:373 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:531 +msgid "The subscription's start date." msgstr "" -#. translators: 1: old subscription status 2: new subscription status -#: includes/class-wc-subscription.php:568 -msgid "Status changed from %1$s to %2$s." +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:378 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:536 +msgid "The subscription's trial date" msgstr "" -#. translators: %s: new order status -#: includes/class-wc-subscription.php:582 -msgid "Status set to %s." +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:383 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:541 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:436 +msgid "The subscription's next payment date." msgstr "" -#: includes/class-wc-subscription.php:596 -msgid "Error during subscription status transition." +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:388 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:546 +msgid "The subscription's end date." msgstr "" -#. translators: placeholder is human time diff (e.g. "3 weeks") -#: includes/class-wc-subscription.php:1192 -#: includes/class-wc-subscriptions-manager.php:2289 -msgid "In %s" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:185 +msgid "Customer ID is invalid." msgstr "" -#. translators: placeholder is human time diff (e.g. "3 weeks") -#: includes/class-wc-subscription.php:1195 -#: includes/wcs-formatting-functions.php:246 -msgid "%s ago" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:502 +msgid "The status to transition the subscription to. Unlike the \"status\" param, this will calculate and update the subscription dates." msgstr "" -#: includes/class-wc-subscription.php:1202 -msgid "Not yet ended" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:551 +msgid "The subscription's original subscription ID if this is a resubscribed subscription." msgstr "" -#: includes/class-wc-subscription.php:1205 -msgid "Not cancelled" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:557 +msgid "The subscription's resubscribed subscription ID." msgstr "" -#: includes/class-wc-subscription.php:1210 -msgctxt "original denotes there is no date to display" -msgid "-" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:563 +msgid "The date the subscription's latest order was completed, in GMT." msgstr "" -#: includes/class-wc-subscription.php:1318 -msgid "The creation date of a subscription can not be deleted, only updated." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:569 +msgid "The date the subscription's latest order was paid, in GMT." msgstr "" -#: includes/class-wc-subscription.php:1321 -msgid "The start date of a subscription can not be deleted, only updated." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:575 +msgid "Removed line items data." msgstr "" -#. translators: %s: date type (e.g. "trial_end"). -#: includes/class-wc-subscription.php:1326 -msgid "The %s date of a subscription can not be deleted. You must delete the order." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:582 +msgid "Item ID." msgstr "" -#. translators: %d: subscription ID. -#. translators: %d: order ID. -#: includes/class-wc-subscription.php:1335 -#: includes/class-wc-subscription.php:2434 -msgid "Subscription #%d: " +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:588 +msgid "Product name." msgstr "" -#: includes/class-wc-subscription.php:1749 -msgid "Payment status marked complete." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:594 +msgid "Product SKU." msgstr "" -#: includes/class-wc-subscription.php:1777 -msgid "Payment failed." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:600 +msgid "Product ID." msgstr "" -#: includes/class-wc-subscription.php:1782 -msgid "Subscription Cancelled: maximum number of failed payments reached." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:605 +msgid "Variation ID, if applicable." msgstr "" -#: includes/class-wc-subscription.php:1892 -msgid "The \"all\" value for $order_type parameter is deprecated. It was a misnomer, as it did not return resubscribe orders. It was also inconsistent with order type values accepted by wcs_get_subscription_orders(). Use array( \"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or \"any\" to receive all order types, including switch and resubscribe." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:610 +msgid "Quantity ordered." msgstr "" -#: includes/class-wc-subscription.php:2090 -#: wcs-functions.php:828 -msgid "Payment method meta must be an array." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:615 +msgid "Tax class of product." msgstr "" -#: includes/class-wc-subscription.php:2326 -msgid "Invalid format. First parameter needs to be an array." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:621 +msgid "Product price." msgstr "" -#: includes/class-wc-subscription.php:2330 -msgid "Invalid data. First parameter was empty when passed to update_dates()." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:627 +msgid "Line subtotal (before discounts)." msgstr "" -#: includes/class-wc-subscription.php:2337 -msgid "Invalid data. First parameter has a date that is not in the registered date types." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:632 +msgid "Line subtotal tax (before discounts)." msgstr "" -#. translators: placeholder is date type (e.g. "end", "next_payment"...) -#: includes/class-wc-subscription.php:2364 -msgctxt "appears in an error message if date is wrong format" -msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:637 +msgid "Line total (after discounts)." msgstr "" -#. translators: %s: date type (e.g. "end"). -#: includes/class-wc-subscription.php:2402 -msgid "The %s date must occur after the cancellation date." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:642 +msgid "Line total tax (after discounts)." msgstr "" -#. translators: %s: date type (e.g. "end"). -#: includes/class-wc-subscription.php:2408 -msgid "The %s date must occur after the last payment date." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:647 +msgid "Line taxes." msgstr "" -#. translators: %s: date type (e.g. "end"). -#: includes/class-wc-subscription.php:2413 -msgid "The %s date must occur after the next payment date." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:655 +msgid "Tax rate ID." msgstr "" -#. translators: %s: date type (e.g. "end"). -#: includes/class-wc-subscription.php:2419 -msgid "The %s date must occur after the trial end date." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:661 +msgid "Tax total." msgstr "" -#. translators: %s: date type (e.g. "next_payment"). -#: includes/class-wc-subscription.php:2424 -msgid "The %s date must occur after the start date." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:667 +msgid "Tax subtotal." msgstr "" -#: includes/class-wc-subscription.php:2454 -#: includes/class-wc-subscriptions-checkout.php:328 -#: includes/wcs-order-functions.php:308 -msgid "Backordered" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:676 +msgid "Removed line item meta data." msgstr "" -#: includes/class-wc-subscriptions-addresses.php:47 -msgid "Change address" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:684 +msgid "Meta key." msgstr "" -#: includes/class-wc-subscriptions-addresses.php:71 -msgid "Both the shipping address used for the subscription and your default shipping address for future purchases will be updated." +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:690 +msgid "Meta label." msgstr "" -#. translators: $1: address type (Shipping Address / Billing Address), $2: opening tag, $3: closing tag -#: includes/class-wc-subscriptions-addresses.php:84 -msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:696 +msgid "Meta value." msgstr "" -#. translators: %s: subscription ID. -#. translators: %s: order number. -#. translators: placeholder is a subscription ID. -#: includes/class-wc-subscriptions-addresses.php:207 -#: includes/class-wc-subscriptions-change-payment-gateway.php:737 -#: includes/class-wcs-query.php:111 -msgctxt "hash before order number" -msgid "Subscription #%s" +#. translators: 1-2: opening/closing tags, 3: Subscriptions version. +#: includes/class-wc-subscriptions-plugin.php:55 +msgid "%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce Subscriptions%2$s comes with that plugin's functionality packaged into the core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to avoid any conflicts." msgstr "" -#. translators: %s: address type (eg. 'billing' or 'shipping'). -#: includes/class-wc-subscriptions-addresses.php:213 -msgctxt "change billing or shipping address" -msgid "Change %s address" +#: includes/class-wc-subscriptions-plugin.php:59 +msgid "Installed Plugins" msgstr "" -#: includes/class-wc-subscriptions-cart-validator.php:56 -#: woocommerce-subscriptions.php:520 -msgid "A subscription renewal has been removed from your cart. Multiple subscriptions can not be purchased at the same time." +#. translators: $1-$2: opening and closing tags, $3-$4: opening and closing tags. +#: includes/class-wc-subscriptions-plugin.php:196 +msgid "%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou're ready to start selling subscriptions!%4$s" msgstr "" -#: includes/class-wc-subscriptions-cart-validator.php:62 -#: woocommerce-subscriptions.php:526 -msgid "A subscription has been removed from your cart. Due to payment gateway restrictions, different subscription products can not be purchased at the same time." +#: includes/class-wc-subscriptions-plugin.php:214 +msgid "Add a Subscription Product" msgstr "" -#: includes/class-wc-subscriptions-cart-validator.php:68 -#: woocommerce-subscriptions.php:532 -msgid "A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time." -msgstr "" - -#: includes/class-wc-subscriptions-cart-validator.php:111 -msgid "Your cart has been emptied of subscription products. Only one subscription product can be purchased at a time." -msgstr "" - -#: includes/class-wc-subscriptions-cart-validator.php:136 -#: includes/class-wc-subscriptions-cart.php:1503 -msgid "That subscription product can not be added to your cart as it already contains a subscription renewal." -msgstr "" - -#: includes/class-wc-subscriptions-cart.php:993 -msgid "Please enter a valid postcode/ZIP." -msgstr "" - -#: includes/class-wc-subscriptions-cart.php:1238 -msgid "Invalid recurring shipping method." -msgstr "" - -#: includes/class-wc-subscriptions-cart.php:2179 -msgid "now" -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:181 -msgid "Sorry, this subscription change payment method request is invalid and cannot be processed." -msgstr "" - -#. translators: placeholder is next payment's date -#: includes/class-wc-subscriptions-change-payment-gateway.php:205 -msgid " Next payment is due %s." -msgstr "" - -#. translators: placeholder is either empty or "Next payment is due..." -#: includes/class-wc-subscriptions-change-payment-gateway.php:211 -msgid "Choose a new payment method.%s" -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:247 -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:106 -msgid "There was an error with your request. Please try again." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:250 -#: includes/class-wcs-template-loader.php:28 -#: includes/wcs-helper-functions.php:286 -msgid "Invalid Subscription." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:253 -#: includes/class-wcs-cart-resubscribe.php:78 -#: includes/class-wcs-cart-resubscribe.php:129 -#: includes/class-wcs-user-change-status-handler.php:111 -#: includes/early-renewal/class-wcs-cart-early-renewal.php:95 -msgid "That doesn't appear to be one of your subscriptions." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:256 -#: includes/class-wcs-query.php:255 -msgid "The payment method can not be changed for that subscription." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:259 -msgid "Invalid order." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:277 -msgctxt "label on button, imperative" -msgid "Change payment" -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:279 -msgctxt "label on button, imperative" -msgid "Add payment" -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:340 -msgid "Payment method updated." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:340 -msgid "Payment method added." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:380 -#: includes/class-wc-subscriptions-change-payment-gateway.php:382 -msgid "Payment method updated for all your current subscriptions." -msgstr "" - -#. translators: 1: old payment title, 2: new payment title. -#: includes/class-wc-subscriptions-change-payment-gateway.php:530 -msgctxt "%1$s: old payment title, %2$s: new payment title" -msgid "Payment method changed from \"%1$s\" to \"%2$s\" by the subscriber from their account page." -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:705 -#: includes/class-wc-subscriptions-change-payment-gateway.php:743 -msgctxt "the page title of the change payment method form" -msgid "Change payment method" -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:707 -#: includes/class-wc-subscriptions-change-payment-gateway.php:748 -msgctxt "the page title of the add payment method form" -msgid "Add payment method" -msgstr "" - -#: includes/class-wc-subscriptions-change-payment-gateway.php:793 -msgid "Please log in to your account below to choose a new payment method for your subscription." -msgstr "" - -#. translators: placeholder is an internal error number -#: includes/class-wc-subscriptions-checkout.php:188 -#: includes/class-wc-subscriptions-checkout.php:374 -msgid "Error %d: Unable to create subscription. Please try again." -msgstr "" - -#. translators: placeholder is an internal error number -#: includes/class-wc-subscriptions-checkout.php:205 -msgid "Error %d: Unable to add tax to subscription. Please try again." -msgstr "" - -#. translators: placeholder is an internal error number -#: includes/class-wc-subscriptions-checkout.php:217 -msgid "Error %d: Unable to create order. Please try again." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:164 -msgid "Sign Up Fee Discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:165 -msgid "Sign Up Fee % Discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:166 -msgid "Recurring Product Discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:167 -msgid "Recurring Product % Discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:457 -msgid "Sorry, this coupon is only valid for an initial payment and the cart does not require an initial payment." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:463 -msgid "Sorry, this coupon is only valid for new subscriptions." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:468 -msgid "Sorry, this coupon is only valid for subscription products." -msgstr "" - -#. translators: 1$: coupon code that is being removed -#: includes/class-wc-subscriptions-coupon.php:474 -msgid "Sorry, the \"%1$s\" coupon is only valid for renewals." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:479 -msgid "Sorry, this coupon is only valid for subscription products with a sign-up fee." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:505 -msgid "Sorry, recurring coupons can only be applied to subscriptions or subscription orders." -msgstr "" - -#. translators: placeholder is coupon code -#: includes/class-wc-subscriptions-coupon.php:509 -msgid "Sorry, \"%s\" can only be applied to subscription parent orders which contain a product with signup fees." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:512 -msgid "Sorry, only recurring coupons can be applied to subscriptions." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:694 -msgid "Renewal % discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:695 -msgid "Renewal product discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:696 -msgid "Renewal cart discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:697 -msgid "Initial payment discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:714 -msgid "Renewal Discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:717 -msgid "Discount" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:933 -msgid "Sorry, it seems there are no available payment methods which support the recurring coupon you are using. Please contact us if you require assistance or wish to make alternate arrangements." -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:948 -msgid "Active for x payments" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:949 -msgid "Unlimited payments" -msgstr "" - -#: includes/class-wc-subscriptions-coupon.php:950 -msgid "Coupon will be limited to the given number of payments. It will then be automatically removed from the subscription. \"Payments\" also includes the initial subscription payment." -msgstr "" - -#. translators: %1$s is the coupon code, %2$d is the number of payment usages -#: includes/class-wc-subscriptions-coupon.php:1047 -msgid "Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d time." -msgid_plural "Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d times." -msgstr[0] "" -msgstr[1] "" - -#. translators: %d refers to the number of payments the coupon can be used for. -#: includes/class-wc-subscriptions-coupon.php:1082 -msgid "Active for %d payment" -msgid_plural "Active for %d payments" -msgstr[0] "" -msgstr[1] "" - -#: includes/class-wc-subscriptions-coupon.php:1086 -msgid "Active for unlimited payments" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:87 -#: includes/class-wc-subscriptions-manager.php:1903 -#: includes/class-wc-subscriptions-manager.php:1921 -msgctxt "used in order note as reason for why subscription status changed" -msgid "Subscription renewal payment due:" -msgstr "" - -#. translators: placeholder is an order note. -#: includes/class-wc-subscriptions-manager.php:124 -msgid "Error: Unable to create renewal order with note \"%s\"" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:134 -msgid "Manual renewal order awaiting customer payment." -msgstr "" - -#. translators: placeholder is a subscription ID. -#. translators: %d: subscription ID. -#: includes/class-wc-subscriptions-manager.php:167 -#: includes/gateways/class-wc-subscriptions-payment-gateways.php:215 -msgid "Subscription doesn't exist in scheduled action: %d" -msgstr "" - -#. translators: $1: order number, $2: error message -#: includes/class-wc-subscriptions-manager.php:304 -msgid "Failed to activate subscription status for order #%1$s: %2$s" -msgstr "" - -#. translators: $1: order number, $2: error message -#: includes/class-wc-subscriptions-manager.php:332 -msgid "Failed to update subscription status after order #%1$s was put on-hold: %2$s" -msgstr "" - -#. translators: $1: order number, $2: error message -#: includes/class-wc-subscriptions-manager.php:360 -msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" -msgstr "" - -#. translators: $1: order number, $2: error message -#: includes/class-wc-subscriptions-manager.php:388 -msgid "Failed to set subscription as expired for order #%1$s: %2$s" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:414 -msgid "Subscription sign up failed." -msgstr "" - -#. translators: $1: order number, $2: error message -#: includes/class-wc-subscriptions-manager.php:424 -msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:498 -msgid "Error: Unable to create subscription. Please try again." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:520 -msgid "Error: Unable to add product to created subscription. Please try again." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:565 -msgid "Pending subscription created." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1048 -#: wcs-functions.php:233 -msgctxt "Subscription status" -msgid "Active" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1051 -#: wcs-functions.php:235 -msgctxt "Subscription status" -msgid "Cancelled" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1054 -#: wcs-functions.php:237 -msgctxt "Subscription status" -msgid "Expired" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1057 -#: wcs-functions.php:232 -msgctxt "Subscription status" -msgid "Pending" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1060 -msgctxt "Subscription status" -msgid "Failed" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1064 -msgctxt "Subscription status" -msgid "On-hold" -msgstr "" - -#. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. "Jan") -#: includes/class-wc-subscriptions-manager.php:1816 -msgctxt "used in a select box" -msgid "%1$s-%2$s" -msgstr "" - -#. translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd like -#: includes/class-wc-subscriptions-manager.php:1829 -msgid "%1$s%2$s, %3$s @ %4$s : %5$s" -msgstr "" - -#. translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input. Change the order if you'd like -#: includes/class-wc-subscriptions-manager.php:1833 -msgid "%1$s%2$s, %3$s" -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:1838 -msgid "Change" -msgstr "" - -#. translators: placeholder is subscription ID -#: includes/class-wc-subscriptions-manager.php:2171 -msgid "Failed sign-up for subscription %s." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:2262 -msgid "Invalid security token, please reload the page and try again." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:2266 -msgid "Only store managers can edit payment dates." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:2270 -msgid "Please enter all date fields." -msgstr "" - -#: includes/class-wc-subscriptions-manager.php:2295 -msgid "Date Changed" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:379 -msgid "Your subscription will be activated when payment clears." -msgid_plural "Your subscriptions will be activated when payment clears." -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholders are opening and closing link tags -#: includes/class-wc-subscriptions-order.php:386 -msgid "View the status of your subscription in %1$syour account%2$s." -msgid_plural "View the status of your subscriptions in %1$syour account%2$s." -msgstr[0] "" -msgstr[1] "" - -#: includes/class-wc-subscriptions-order.php:449 -msgid "Subscription Relationship" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:469 -msgid "Renewal Order" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:471 -msgid "Resubscribe Order" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:473 -msgid "Parent Order" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:696 -msgid "All orders types" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:699 -msgctxt "An order type" -msgid "Original" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:700 -msgctxt "An order type" -msgid "Subscription Parent" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:701 -msgctxt "An order type" -msgid "Subscription Renewal" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:702 -msgctxt "An order type" -msgid "Subscription Resubscribe" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:703 -msgctxt "An order type" -msgid "Subscription Switch" -msgstr "" - -#: includes/class-wc-subscriptions-order.php:704 -msgctxt "An order type" -msgid "Non-subscription" -msgstr "" - -#. translators: $1: opening link tag, $2: order number, $3: closing link tag -#: includes/class-wc-subscriptions-order.php:1007 -msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s." -msgstr "" - -#. translators: %1$s refers to the price. This string is meant to prefix another string below, e.g. "$5 now, and $5 on March 15th each year" -#: includes/class-wc-subscriptions-product.php:287 -msgid "%1$s now, and " -msgstr "" - -#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday"). -#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday") -#. translators: %1$: recurring amount (e.g. "$15"), %2$: subscription period (e.g. "month") (e.g. "$15 every 2nd month") -#: includes/class-wc-subscriptions-product.php:296 -#: includes/wcs-formatting-functions.php:116 -#: includes/wcs-formatting-functions.php:201 -msgid "%1$s every %2$s" -msgstr "" - -#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday"). -#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday") -#: includes/class-wc-subscriptions-product.php:300 -#: includes/wcs-formatting-functions.php:125 -msgid "%1$s every %2$s on %3$s" -msgstr "" - -#. translators: placeholder is recurring amount. -#. translators: placeholder is recurring amount -#: includes/class-wc-subscriptions-product.php:311 -#: includes/wcs-formatting-functions.php:143 -msgid "%s on the last day of each month" -msgstr "" - -#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month"). -#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") -#: includes/class-wc-subscriptions-product.php:315 -#: includes/wcs-formatting-functions.php:146 -msgid "%1$s on the %2$s of each month" -msgstr "" - -#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month"). -#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month") -#: includes/class-wc-subscriptions-product.php:324 -#: includes/wcs-formatting-functions.php:162 -msgid "%1$s on the last day of every %2$s month" -msgstr "" - -#. translators: 1$: on the, 2$: day of every, 3$: month (e.g. "$10 on the 23rd day of every 2nd month"). -#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") -#: includes/class-wc-subscriptions-product.php:331 -#: includes/wcs-formatting-functions.php:165 -msgid "%1$s on the %2$s day of every %3$s month" -msgstr "" - -#. translators: 1$: on, 2$: , 3$: each year (e.g. "$15 on March 15th each year"). -#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") -#: includes/class-wc-subscriptions-product.php:343 -#: includes/wcs-formatting-functions.php:178 -msgid "%1$s on %2$s %3$s each year" -msgstr "" - -#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd"). -#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") -#: includes/class-wc-subscriptions-product.php:351 -#: includes/wcs-formatting-functions.php:187 -msgid "%1$s on %2$s %3$s every %4$s year" -msgstr "" - -#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month"). -#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month") -#: includes/class-wc-subscriptions-product.php:363 -#: includes/wcs-formatting-functions.php:198 -msgid "%1$s / %2$s" -msgid_plural "%1$s every %2$s" -msgstr[0] "" -msgstr[1] "" - -#. translators: billing period (e.g. "every week"). -#: includes/class-wc-subscriptions-product.php:373 -msgid "every %s" -msgstr "" - -#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years"). -#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years") -#: includes/class-wc-subscriptions-product.php:383 -#: includes/wcs-formatting-functions.php:209 -msgid "%1$s for %2$s" -msgstr "" - -#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years"), 2$: trial length (e.g.: "with 4 months free trial"). -#: includes/class-wc-subscriptions-product.php:389 -msgid "%1$s with %2$s free trial" -msgstr "" - -#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a $30 sign-up fee"). -#: includes/class-wc-subscriptions-product.php:394 -msgid "%1$s and a %2$s sign-up fee" -msgstr "" - -#: includes/class-wc-subscriptions-product.php:965 -msgid "This variation can not be removed because it is associated with active subscriptions. To remove this variation, please cancel and delete the subscriptions for it." -msgstr "" - -#. translators: placeholder is order ID -#: includes/class-wc-subscriptions-renewal-order.php:161 -msgid "Order %s created to record renewal." -msgstr "" - -#: includes/class-wc-subscriptions-renewal-order.php:181 -msgid "Subscription renewal orders cannot be cancelled." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:188 -msgid "You have a subscription to this product. Choosing a new subscription will replace your existing subscription." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:190 -msgid "Choose a new subscription." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:230 -#: includes/class-wc-subscriptions-switcher.php:1261 -msgid "Your cart contained an invalid subscription switch request. It has been removed." -msgid_plural "Your cart contained invalid subscription switch requests. They have been removed." -msgstr[0] "" -msgstr[1] "" - -#: includes/class-wc-subscriptions-switcher.php:272 -msgid "You have already subscribed to this product and it is limited to one per customer. You can not purchase the product again." -msgstr "" - -#. translators: 1$: is the "You have already subscribed to this product" notice, 2$-4$: opening/closing link tags, 3$: an order number -#: includes/class-wc-subscriptions-switcher.php:281 -msgid "%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your subscription." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:376 -msgid "Switching" -msgstr "" - -#. translators: placeholders are opening and closing link tags -#: includes/class-wc-subscriptions-switcher.php:379 -msgid "Allow subscribers to switch (upgrade or downgrade) between different subscriptions. %1$sLearn more%2$s." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:389 -msgid "Prorate Recurring Payment" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:390 -msgid "When switching to a subscription with a different recurring payment or billing period, should the price paid for the existing billing period be prorated when switching to the new subscription?" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:397 -#: includes/class-wc-subscriptions-switcher.php:431 -msgctxt "when to allow a setting" -msgid "Never" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:398 -msgctxt "when to prorate recurring fee when switching" -msgid "For Upgrades of Virtual Subscription Products Only" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:399 -msgctxt "when to prorate recurring fee when switching" -msgid "For Upgrades of All Subscription Products" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:400 -msgctxt "when to prorate recurring fee when switching" -msgid "For Upgrades & Downgrades of Virtual Subscription Products Only" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:401 -msgctxt "when to prorate recurring fee when switching" -msgid "For Upgrades & Downgrades of All Subscription Products" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:407 -msgid "Prorate Sign up Fee" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:408 -msgid "When switching to a subscription with a sign up fee, you can require the customer pay only the gap between the existing subscription's sign up fee and the new subscription's sign up fee (if any)." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:415 -msgctxt "when to prorate signup fee when switching" -msgid "Never (do not charge a sign up fee)" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:416 -msgctxt "when to prorate signup fee when switching" -msgid "Never (charge the full sign up fee)" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:417 -msgctxt "when to prorate signup fee when switching" -msgid "Always" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:423 -msgid "Prorate Subscription Length" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:424 -msgid "When switching to a subscription with a length, you can take into account the payments already completed by the customer when determining how many payments the subscriber needs to make for the new subscription." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:432 -#: includes/class-wc-subscriptions-synchroniser.php:235 -msgctxt "when to prorate first payment / subscription length" -msgid "For Virtual Subscription Products Only" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:433 -#: includes/class-wc-subscriptions-synchroniser.php:236 -msgctxt "when to prorate first payment / subscription length" -msgid "For All Subscription Products" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:439 -msgid "Switch Button Text" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:440 -msgid "Customise the text displayed on the button next to the subscription on the subscriber's account page. The default is \"Switch Subscription\", but you may wish to change this to \"Upgrade\" or \"Change Subscription\"." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:444 -#: includes/class-wc-subscriptions-switcher.php:542 -#: includes/class-wc-subscriptions-switcher.php:2575 -msgid "Upgrade or Downgrade" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:479 -msgid "Allow Switching" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:486 -msgctxt "when to allow switching" -msgid "Between Subscription Variations" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:490 -msgctxt "when to allow switching" -msgid "Between Grouped Subscriptions" -msgstr "" - -#. translators: %s: order number. -#: includes/class-wc-subscriptions-switcher.php:1120 -msgid "Switch order cancelled due to a new switch order being created #%s." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1208 -msgid "Switch Order" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1223 -msgid "Switched Subscription" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1389 -msgid "You can only switch to a subscription product." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1395 -msgid "We can not find your old subscription item." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1417 -msgid "You can not switch to the same subscription." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1464 -msgid "You can not switch this subscription. It appears you do not own the subscription." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1505 -msgid "There was an error locating the switch details." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1868 -msgctxt "a switch type" -msgid "Downgrade" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1871 -msgctxt "a switch type" -msgid "Upgrade" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1874 -msgctxt "a switch type" -msgid "Crossgrade" -msgstr "" - -#. translators: %1: product subtotal, %2: HTML span tag, %3: direction (upgrade, downgrade, crossgrade), %4: closing HTML span tag -#: includes/class-wc-subscriptions-switcher.php:1879 -msgctxt "product subtotal string" -msgid "%1$s %2$s(%3$s)%4$s" -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1985 -msgid "The original subscription item being switched cannot be found." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:1987 -msgid "The item on the switch order cannot be found." -msgstr "" - -#. translators: 1$: old item, 2$: new item when switching -#: includes/class-wc-subscriptions-switcher.php:1998 -msgctxt "used in order notes" -msgid "Customer switched from: %1$s to %2$s." -msgstr "" - -#. translators: %s: new item name. -#: includes/class-wc-subscriptions-switcher.php:2001 -msgctxt "used in order notes" -msgid "Customer added %s." -msgstr "" - -#: includes/class-wc-subscriptions-switcher.php:2716 -#: wcs-functions.php:236 -msgctxt "Subscription status" -msgid "Switched" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:48 -msgid "Synchronise renewals" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:49 -msgid "Align the payment date for all customers who purchase this subscription to a specific day of the week or month." -msgstr "" - -#. translators: placeholder is a year (e.g. "2016") -#: includes/class-wc-subscriptions-synchroniser.php:51 -msgctxt "used in subscription product edit screen" -msgid "Align the payment date for this subscription to a specific day of the year. If the date has already taken place this year, the first payment will be processed in %s. Set the day to 0 to disable payment syncing for this product." -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:210 -msgid "Synchronisation" -msgstr "" - -#. translators: placeholders are opening and closing link tags -#: includes/class-wc-subscriptions-synchroniser.php:213 -msgctxt "used in the general subscription options page" -msgid "Align subscription renewal to a specific day of the week, month or year. For example, the first day of the month. %1$sLearn more%2$s." -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:219 -msgid "Align Subscription Renewal Day" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:226 -msgid "Prorate First Renewal" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:227 -msgid "If a subscription is synchronised to a specific day of the week, month or year, charge a prorated amount for the subscription at the time of sign up." -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:233 -msgctxt "when to prorate first payment / subscription length" -msgid "Never (do not charge any recurring amount)" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:234 -msgctxt "when to prorate first payment / subscription length" -msgid "Never (charge the full recurring amount at sign-up)" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:242 -msgid "Sign-up grace period" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:243 -msgctxt "there's a number immediately in front of this text" -msgid "days prior to Renewal Day" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:247 -msgid "Subscriptions created within this many days prior to the Renewal Day will not be charged at sign-up. Set to zero for all new Subscriptions to be charged the full recurring amount. Must be a positive number." -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:311 -msgid "Month for Synchronisation" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:319 -#: templates/admin/deprecated/html-variation-synchronisation.php:36 -#: templates/admin/html-variation-synchronisation.php:42 -msgctxt "input field placeholder for day field for annual subscriptions" -msgid "Day" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:750 -#: includes/class-wc-subscriptions-synchroniser.php:767 -msgid "Do not synchronise" -msgstr "" - -#. translators: placeholder is a day of the week -#: includes/class-wc-subscriptions-synchroniser.php:775 -msgid "%s each week" -msgstr "" - -#. translators: placeholder is a number of day with language specific suffix applied (e.g. "1st", "3rd", "5th", etc...) -#: includes/class-wc-subscriptions-synchroniser.php:781 -msgid "%s day of the month" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:783 -msgid "Last day of the month" -msgstr "" - -#: includes/class-wc-subscriptions-synchroniser.php:831 -msgid "Today!" -msgstr "" - -#. translators: placeholder is a date -#: includes/class-wc-subscriptions-synchroniser.php:838 -msgid "First payment prorated. Next payment: %s" -msgstr "" - -#. translators: placeholder is a date -#: includes/class-wc-subscriptions-synchroniser.php:841 -msgid "First payment: %s" +#: includes/class-wc-subscriptions-plugin.php:215 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:514 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:35 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:34 +msgid "Settings" msgstr "" #: includes/class-wcs-auth.php:39 @@ -3059,433 +1009,269 @@ msgstr "" msgid "View and manage subscriptions" msgstr "" -#: includes/class-wcs-cached-data-manager.php:79 -msgid "Related order caching is now handled by %1$s." +#: includes/class-wcs-call-to-action-button-text-manager.php:33 +msgid "Button Text" msgstr "" -#: includes/class-wcs-cached-data-manager.php:86 -msgid "Customer subscription caching is now handled by %1$s." +#: includes/class-wcs-call-to-action-button-text-manager.php:39 +msgid "Add to Cart Button Text" msgstr "" -#: includes/class-wcs-cached-data-manager.php:110 -#: includes/class-wcs-cached-data-manager.php:240 -msgid "Customer subscription caching is now handled by %1$s and %2$s." +#: includes/class-wcs-call-to-action-button-text-manager.php:40 +msgid "A product displays a button with the text \"Add to cart\". By default, a subscription changes this to \"Sign up now\". You can customise the button text for subscriptions here." msgstr "" -#: includes/class-wcs-cached-data-manager.php:127 -msgid "new related order methods in WCS_Related_Order_Store" +#: includes/class-wcs-call-to-action-button-text-manager.php:44 +#: includes/class-wcs-call-to-action-button-text-manager.php:47 +#: includes/class-wcs-call-to-action-button-text-manager.php:55 +#: includes/class-wcs-call-to-action-button-text-manager.php:58 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:650 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:1204 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:1236 +msgid "Sign up now" msgstr "" -#: includes/class-wcs-cached-data-manager.php:225 -msgid "Weekly" +#: includes/class-wcs-call-to-action-button-text-manager.php:50 +msgid "Place Order Button Text" msgstr "" -#: includes/class-wcs-cart-initial-payment.php:62 -#: includes/class-wcs-cart-renewal.php:194 -msgid "That doesn't appear to be your order." +#: includes/class-wcs-call-to-action-button-text-manager.php:51 +msgid "Use this field to customise the text displayed on the checkout button when an order contains a subscription. Normally the checkout submission button displays \"Place order\". When the cart contains a subscription, this is changed to \"Sign up now\"." msgstr "" -#: includes/class-wcs-cart-renewal.php:210 -msgid "This order can no longer be paid because the corresponding subscription does not require payment at this time." +#: includes/class-wcs-customer-suspension-manager.php:32 +msgid "Customer Suspensions" msgstr "" -#: includes/class-wcs-cart-renewal.php:227 -msgid "Complete checkout to renew your subscription." +#: includes/class-wcs-customer-suspension-manager.php:33 +msgctxt "there's a number immediately in front of this text" +msgid "suspensions per billing period." msgstr "" -#. translators: placeholder is an item name -#: includes/class-wcs-cart-renewal.php:292 -msgid "The %s product has been deleted and can no longer be renewed. Please choose a new product or contact us for assistance." +#: includes/class-wcs-customer-suspension-manager.php:39 +msgid "Set a maximum number of times a customer can suspend their account for each billing period. For example, for a value of 3 and a subscription billed yearly, if the customer has suspended their account 3 times, they will not be presented with the option to suspend their account until the next year. Store managers will always be able to suspend an active subscription. Set this to 0 to turn off the customer suspension feature completely." msgstr "" -#. translators: %s is subscription's number -#: includes/class-wcs-cart-renewal.php:327 -msgid "Subscription #%s has not been added to the cart." +#: includes/class-wcs-customer-suspension-manager.php:110 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:498 +msgid "Suspend" msgstr "" -#. translators: %s is order's number -#: includes/class-wcs-cart-renewal.php:330 -msgid "Order #%s has not been added to the cart." +#: includes/class-wcs-drip-downloads-manager.php:64 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:108 +msgid "Drip Downloadable Content" msgstr "" -#: includes/class-wcs-cart-renewal.php:369 -msgid "We couldn't find the original subscription for an item in your cart. The item was removed." -msgid_plural "We couldn't find the original subscriptions for items in your cart. The items were removed." +#: includes/class-wcs-drip-downloads-manager.php:65 +msgid "Enable dripping for downloadable content on subscription products." +msgstr "" + +#. translators: %s is a line break. +#: includes/class-wcs-drip-downloads-manager.php:70 +msgid "Enabling this grants access to new downloadable files added to a product only after the next renewal is processed.%sBy default, access to new downloadable files added to a product is granted immediately to any customer that has an active subscription with that product." +msgstr "" + +#: includes/class-wcs-limited-recurring-coupon-manager.php:50 +msgid "Active for x payments" +msgstr "" + +#: includes/class-wcs-limited-recurring-coupon-manager.php:51 +msgid "Unlimited payments" +msgstr "" + +#: includes/class-wcs-limited-recurring-coupon-manager.php:52 +msgid "Coupon will be limited to the given number of payments. It will then be automatically removed from the subscription. \"Payments\" also includes the initial subscription payment." +msgstr "" + +#. translators: %1$s is the coupon code, %2$d is the number of payment usages +#: includes/class-wcs-limited-recurring-coupon-manager.php:247 +msgid "Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d time." +msgid_plural "Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d times." msgstr[0] "" msgstr[1] "" -#: includes/class-wcs-cart-renewal.php:376 -msgid "We couldn't find the original renewal order for an item in your cart. The item was removed." -msgid_plural "We couldn't find the original renewal orders for items in your cart. The items were removed." +#. translators: %d refers to the number of payments the coupon can be used for. +#: includes/class-wcs-limited-recurring-coupon-manager.php:282 +msgid "Active for %d payment" +msgid_plural "Active for %d payments" msgstr[0] "" msgstr[1] "" -#: includes/class-wcs-cart-renewal.php:643 -msgid "All linked subscription items have been removed from the cart." +#: includes/class-wcs-limited-recurring-coupon-manager.php:286 +msgid "Active for unlimited payments" msgstr "" -#: includes/class-wcs-cart-renewal.php:672 -msgctxt "Used in WooCommerce by removed item notification: \"_All linked subscription items were_ removed. Undo?\" Filter for item title." -msgid "All linked subscription items were" +#: includes/class-wcs-limited-recurring-coupon-manager.php:378 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:1148 +msgid "Sorry, it seems there are no available payment methods which support the recurring coupon you are using. Please contact us if you require assistance or wish to make alternate arrangements." msgstr "" -#: includes/class-wcs-cart-resubscribe.php:70 -msgid "There was an error with your request to resubscribe. Please try again." +#: includes/class-wcs-manual-renewal-manager.php:31 +msgctxt "option section heading" +msgid "Renewals" msgstr "" -#: includes/class-wcs-cart-resubscribe.php:74 -#: includes/early-renewal/class-wcs-cart-early-renewal.php:91 -msgid "That subscription does not exist. Has it been deleted?" +#: includes/class-wcs-manual-renewal-manager.php:37 +msgid "Manual Renewal Payments" msgstr "" -#: includes/class-wcs-cart-resubscribe.php:82 -msgid "You can not resubscribe to that subscription. Please contact us if you need assistance." -msgstr "" - -#: includes/class-wcs-cart-resubscribe.php:91 -#: includes/class-wcs-cart-resubscribe.php:119 -msgid "Complete checkout to resubscribe." -msgstr "" - -#. translators: %s: order number. -#: includes/class-wcs-cart-resubscribe.php:320 -msgid "Customer resubscribed in order #%s" -msgstr "" - -#: includes/class-wcs-change-payment-method-admin.php:122 -msgid "Please choose a valid payment gateway to change to." -msgstr "" - -#: includes/class-wcs-failed-scheduled-action-manager.php:134 -msgid "Ignore this error" -msgstr "" - -#: includes/class-wcs-failed-scheduled-action-manager.php:139 -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:106 -msgid "Learn more" -msgstr "" - -#: includes/class-wcs-limiter.php:46 -msgid "Limit subscription" +#: includes/class-wcs-manual-renewal-manager.php:38 +msgid "Accept Manual Renewals" msgstr "" #. translators: placeholders are opening and closing link tags -#: includes/class-wcs-limiter.php:48 -msgid "Only allow a customer to have one subscription to this product. %1$sLearn more%2$s." +#: includes/class-wcs-manual-renewal-manager.php:43 +msgid "With manual renewals, a customer's subscription is put on-hold until they login and pay to renew it. %1$sLearn more%2$s." msgstr "" -#: includes/class-wcs-limiter.php:50 -msgid "Do not limit" +#: includes/class-wcs-manual-renewal-manager.php:49 +msgid "Turn off Automatic Payments" msgstr "" -#: includes/class-wcs-limiter.php:51 -msgid "Limit to one active subscription" +#. translators: placeholders are opening and closing link tags +#: includes/class-wcs-manual-renewal-manager.php:54 +msgid "If you don't want new subscription purchases to automatically charge renewal payments, you can turn off automatic payments. Existing automatic subscriptions will continue to charge customers automatically. %1$sLearn more%2$s." msgstr "" -#: includes/class-wcs-limiter.php:52 -msgid "Limit to one of any status" +#: includes/class-wcs-subscriber-role-manager.php:39 +msgid "Roles" msgstr "" -#: includes/class-wcs-my-account-auto-renew-toggle.php:153 -msgid "Auto Renewal Toggle" +#. translators: placeholders are tags +#: includes/class-wcs-subscriber-role-manager.php:42 +msgid "Choose the default roles to assign to active and inactive subscribers. For record keeping purposes, a user account must be created for subscribers. Users with the %1$sadministrator%2$s role, such as yourself, will never be allocated these roles to prevent locking out administrators." msgstr "" -#: includes/class-wcs-my-account-auto-renew-toggle.php:154 -msgid "Display the auto renewal toggle" +#: includes/class-wcs-subscriber-role-manager.php:46 +msgid "Subscriber Default Role" msgstr "" -#: includes/class-wcs-my-account-auto-renew-toggle.php:155 -msgid "Allow customers to turn on and off automatic renewals from their View Subscription page." +#: includes/class-wcs-subscriber-role-manager.php:47 +msgid "When a subscription is activated, either manually or after a successful purchase, new users will be assigned this role." msgstr "" -#: includes/class-wcs-my-account-payment-methods.php:80 -msgid "The deleted payment method was used for automatic subscription payments, we couldn't find an alternative token payment method token to change your subscriptions to." +#: includes/class-wcs-subscriber-role-manager.php:57 +msgid "Inactive Subscriber Role" msgstr "" -#. translators: 1: deleted token, 2: new token. -#: includes/class-wcs-my-account-payment-methods.php:98 -msgctxt "used in subscription note" -msgid "Payment method meta updated after customer deleted a token from their My Account page. Payment meta changed from %1$s to %2$s" +#: includes/class-wcs-subscriber-role-manager.php:58 +msgid "If a subscriber's subscription is manually cancelled or expires, she will be assigned this role." msgstr "" -#. translators: $1: the token/credit card label, 2$-3$: opening and closing strong and link tags -#: includes/class-wcs-my-account-payment-methods.php:103 -msgid "The deleted payment method was used for automatic subscription payments. To avoid failed renewal payments in future the subscriptions using this payment method have been updated to use your %1$s. To change the payment method of individual subscriptions go to your %2$sMy Account > Subscriptions%3$s page." +#: includes/class-wcs-upgrade-notice-manager.php:80 +msgctxt "plugin version number used in admin notice" +msgid "3.1" msgstr "" -#. translators: 1: token display name, 2: opening link tag, 4: closing link tag, 3: opening link tag. -#: includes/class-wcs-my-account-payment-methods.php:158 -msgid "Would you like to update your subscriptions to use this new payment method - %1$s?%2$sYes%4$s | %3$sNo%4$s" +#: includes/class-wcs-upgrade-notice-manager.php:85 +msgid "v3 REST API endpoint support" msgstr "" -#. translators: 1: previous token, 2: new token. -#: includes/class-wcs-my-account-payment-methods.php:199 -msgctxt "used in subscription note" -msgid "Payment method meta updated after customer changed their default token and opted to update their subscriptions. Payment meta changed from %1$s to %2$s" +#. translators: 1-3: opening/closing
    tags - link to documentation. +#: includes/class-wcs-upgrade-notice-manager.php:88 +msgid "Webhook and REST API users can now use v3 subscription endpoints. Click here to %1$slearn more%2$s about the REST API and check out the technical API docs %3$shere%2$s." msgstr "" -#. translators: 1$-2$: opening and closing tags. -#: includes/class-wcs-permalink-manager.php:91 -msgid "Error saving Subscriptions endpoints: %1$sSubscriptions%2$s, %1$sView subscription%2$s and %1$sSubscription payment method%2$s cannot be the same. The changes have been reverted." +#: includes/class-wcs-upgrade-notice-manager.php:95 +msgid "WooCommerce checkout and cart blocks integration" msgstr "" -#. translators: %s: invalid type of update argument. -#: includes/class-wcs-post-meta-cache-manager.php:199 -msgid "Invalid update type: %s. Post update types supported are \"add\" or \"delete\". Updates are done on post meta directly." +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/class-wcs-upgrade-notice-manager.php:98 +msgid "Subscriptions is now compatible with the WooCommerce cart and checkout blocks. You can learn more about the compatibility status of the cart & checkout blocks %1$shere%2$s." msgstr "" -#. translators: placeholder is a page number. -#: includes/class-wcs-query.php:116 -msgid "Subscriptions (page %d)" +#. translators: placeholder is Subscription version string ('3.1') +#: includes/class-wcs-upgrade-notice-manager.php:105 +msgid "Welcome to WooCommerce Subscriptions %s!" msgstr "" -#: includes/class-wcs-query.php:143 -msgid "My Subscription" -msgstr "" - -#: includes/class-wcs-query.php:300 -msgid "Endpoint for the My Account → Subscriptions page" -msgstr "" - -#: includes/class-wcs-query.php:308 -msgid "View subscription" -msgstr "" - -#: includes/class-wcs-query.php:309 -msgid "Endpoint for the My Account → View Subscription page" -msgstr "" - -#: includes/class-wcs-query.php:317 -msgid "Subscription payment method" -msgstr "" - -#: includes/class-wcs-query.php:318 -msgid "Endpoint for the My Account → Change Subscription Payment Method page" -msgstr "" - -#. translators: %d: subscription ID. -#: includes/class-wcs-remove-item.php:79 -msgctxt "hash before subscription ID" -msgid "Subscription #%d does not exist." -msgstr "" - -#. translators: 1$: product name, 2$: product id -#: includes/class-wcs-remove-item.php:114 -msgctxt "used in order note" -msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." -msgstr "" - -#: includes/class-wcs-remove-item.php:119 -msgid "Your request to undo your previous action was unsuccessful." -msgstr "" - -#. translators: 1$: product name, 2$: product id -#: includes/class-wcs-remove-item.php:137 -msgctxt "used in order note" -msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." -msgstr "" - -#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags -#: includes/class-wcs-remove-item.php:140 -msgid "You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" -msgstr "" - -#: includes/class-wcs-remove-item.php:176 -#: includes/class-wcs-user-change-status-handler.php:107 -msgid "Security error. Please contact us if you need assistance." -msgstr "" - -#: includes/class-wcs-remove-item.php:180 -msgid "You cannot modify a subscription that does not belong to you." -msgstr "" - -#: includes/class-wcs-remove-item.php:184 -msgid "You cannot remove an item that does not exist. " -msgstr "" - -#: includes/class-wcs-remove-item.php:188 -msgid "The item was not removed because this Subscription's payment method does not support removing an item." -msgstr "" - -#: includes/class-wcs-retry-manager.php:120 -msgctxt "table heading" -msgid "Renewal Payment Retry" -msgstr "" - -#: includes/class-wcs-retry-manager.php:230 -msgctxt "used in order note as reason for why status changed" -msgid "Retry rule applied:" -msgstr "" - -#: includes/class-wcs-retry-manager.php:268 -msgctxt "used in order note as reason for why status changed" -msgid "Retry rule reapplied:" -msgstr "" - -#: includes/class-wcs-retry-manager.php:327 -msgctxt "used in order note as reason for why order status changed" -msgid "Subscription renewal payment retry:" -msgstr "" - -#: includes/class-wcs-retry-manager.php:331 -msgctxt "used in order note as reason for why subscription status changed" -msgid "Subscription renewal payment retry:" -msgstr "" - -#: includes/class-wcs-retry-manager.php:347 -msgid "Payment retry attempted on renewal order with multiple related subscriptions with no payment method in common." -msgstr "" - -#. translators: 1-2: opening/closing tags - linked to staging site, 3: link to live site. -#: includes/class-wcs-staging.php:40 -msgid "Payment processing skipped - renewal order created on %1$sstaging site%2$s under staging site lock. Live site is at %3$s" -msgstr "" - -#: includes/class-wcs-staging.php:55 -msgid "staging" -msgstr "" - -#: includes/class-wcs-staging.php:83 -msgid "Subscription locked to Manual Renewal while the store is in staging mode. Payment method changes will take effect in live mode." -msgstr "" - -#. translators: placeholder is a payment method title. -#: includes/class-wcs-staging.php:97 -msgid "Subscription locked to Manual Renewal while the store is in staging mode. Live payment method: %s" -msgstr "" - -#. translators: placeholder is a switch type. -#: includes/class-wcs-switch-cart-item.php:303 -msgid "Invalid switch type \"%s\". Switch must be one of: \"upgrade\", \"downgrade\" or \"crossgrade\"." -msgstr "" - -#: includes/class-wcs-switch-totals-calculator.php:190 -msgid "Your cart contained an invalid subscription switch request. It has been removed from your cart." -msgstr "" - -#: includes/class-wcs-template-loader.php:28 -msgid "My Account" -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:57 -msgctxt "order note left on subscription after user action" -msgid "Subscription reactivated by the subscriber from their account page." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:58 -msgctxt "Notice displayed to user confirming their action." -msgid "Your subscription has been reactivated." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:61 -msgid "You can not reactivate that subscription until paying to renew it. Please contact us if you need assistance." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:67 -msgctxt "order note left on subscription after user action" -msgid "Subscription put on hold by the subscriber from their account page." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:68 -msgctxt "Notice displayed to user confirming their action." -msgid "Your subscription has been put on hold." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:71 -msgid "You can not suspend that subscription - the suspension limit has been reached. Please contact us if you need assistance." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:76 -msgctxt "order note left on subscription after user action" -msgid "Subscription cancelled by the subscriber from their account page." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:77 -msgctxt "Notice displayed to user confirming their action." -msgid "Your subscription has been cancelled." -msgstr "" - -#: includes/class-wcs-user-change-status-handler.php:103 -msgid "That subscription does not exist. Please contact us if you need assistance." -msgstr "" - -#. translators: placeholder is subscription's new status, translated -#: includes/class-wcs-user-change-status-handler.php:116 -msgid "That subscription can not be changed to %s. Please contact us if you need assistance." +#: includes/class-wcs-upgrade-notice-manager.php:112 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:163 +msgid "Learn more" msgstr "" #: includes/class-wcs-webhooks.php:110 -msgid " Subscription Created" +msgid " Subscription created" msgstr "" #: includes/class-wcs-webhooks.php:111 -msgid " Subscription Updated" +msgid " Subscription updated" msgstr "" #: includes/class-wcs-webhooks.php:112 -msgid " Subscription Deleted" +msgid " Subscription deleted" msgstr "" #: includes/class-wcs-webhooks.php:113 -msgid " Subscription Switched" +msgid " Subscription switched" msgstr "" -#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:54 -msgid "Generate Customer Subscription Cache" +#: includes/class-wcs-zero-initial-payment-checkout-manager.php:30 +msgid "$0 Initial Checkout" msgstr "" -#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:54 -msgid "This will generate the persistent cache for linking users with subscriptions. The caches will be generated overtime in the background (via Action Scheduler)." +#: includes/class-wcs-zero-initial-payment-checkout-manager.php:31 +msgid "Allow $0 initial checkout without a payment method." msgstr "" -#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:55 -msgid "Delete Customer Subscription Cache" +#: includes/class-wcs-zero-initial-payment-checkout-manager.php:35 +msgid "Allow a subscription product with a $0 initial payment to be purchased without providing a payment method. The customer will be required to provide a payment method at the end of the initial period to keep the subscription active." msgstr "" -#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:55 -msgid "This will clear the persistent cache of all of subscriptions stored against users in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as queries to find a given user's subscriptions are run." -msgstr "" - -#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 -msgid "Generate Related Order Cache" -msgstr "" - -#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 -msgid "This will generate the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. The caches will be generated overtime in the background (via Action Scheduler)." -msgstr "" - -#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 -msgid "Delete Related Order Cache" -msgstr "" - -#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 -msgid "This will clear the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as related order queries are run." -msgstr "" - -#: includes/early-renewal/class-wcs-cart-early-renewal.php:71 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:80 msgid "Renew now" msgstr "" -#: includes/early-renewal/class-wcs-cart-early-renewal.php:99 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:100 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:74 +msgid "That subscription does not exist. Has it been deleted?" +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:104 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:233 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:78 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:129 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:111 +msgid "That doesn't appear to be one of your subscriptions." +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:108 msgid "You can not renew this subscription early. Please contact us if you need assistance." msgstr "" -#: includes/early-renewal/class-wcs-cart-early-renewal.php:105 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:114 msgid "Complete checkout to renew now." msgstr "" -#: includes/early-renewal/class-wcs-cart-early-renewal.php:150 -#: includes/early-renewal/class-wcs-cart-early-renewal.php:198 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:159 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:207 msgctxt "used in order note as reason for why subscription status changed" msgid "Customer requested to renew early:" msgstr "" +#. translators: %s: order ID. +#. translators: placeholder is an order number. +#. translators: placeholder is an order ID. +#. translators: %s: order number. +#: includes/early-renewal/class-wcs-cart-early-renewal.php:318 +#: includes/early-renewal/wcs-early-renewal-functions.php:136 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-row.php:17 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:18 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:158 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:34 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:44 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:33 +msgctxt "hash before order number" +msgid "#%s" +msgstr "" + #. translators: %s: order ID (linked to details page). -#: includes/early-renewal/class-wcs-cart-early-renewal.php:312 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:321 msgid "Order %s created to record early renewal." msgstr "" -#: includes/early-renewal/class-wcs-cart-early-renewal.php:367 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:376 msgid "Cancel" msgstr "" @@ -3514,2361 +1300,543 @@ msgstr "" msgid "Pay now" msgstr "" -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:56 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:57 msgid "Renew early" msgstr "" -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:113 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:73 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php:23 +msgid "Payment:" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:107 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:227 +msgid "There was an error with your request. Please try again." +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:114 msgid "We were unable to locate that subscription, please try again." msgstr "" -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:118 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:119 msgid "You can't renew the subscription at this time. Please try again." msgstr "" -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:128 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:129 msgid "We couldn't create a renewal order for your subscription, please try again." msgstr "" -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:145 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:146 msgid "Payment for the renewal order was unsuccessful with your payment method on file, please try again." msgstr "" -#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:150 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:154 msgid "Your early renewal order was successful." msgstr "" #. translators: placeholder contains a link to the order's edit screen. -#: includes/early-renewal/wcs-early-renewal-functions.php:169 +#: includes/early-renewal/wcs-early-renewal-functions.php:143 msgid "Customer successfully renewed early with order %s." msgstr "" #. translators: placeholder contains a link to the order's edit screen. -#: includes/early-renewal/wcs-early-renewal-functions.php:172 +#: includes/early-renewal/wcs-early-renewal-functions.php:146 msgid "Failed to update subscription dates after customer renewed early with order %s." msgstr "" -#: includes/emails/class-wcs-email-cancelled-subscription.php:26 -msgid "Cancelled Subscription" +#. translators: %d: subscription ID. +#. translators: placeholder is a subscription ID. +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:77 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:167 +msgid "Subscription doesn't exist in scheduled action: %d" msgstr "" -#: includes/emails/class-wcs-email-cancelled-subscription.php:27 -msgid "Cancelled Subscription emails are sent when a customer's subscription is cancelled (either by a store manager, or the customer)." +#. translators: $1-$2: opening and closing tags. Link to documents->payment gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions shop page +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:129 +msgid "Find new gateways that %1$ssupport automatic subscription payments%2$s in the official %3$sWooCommerce Marketplace%4$s." msgstr "" -#: includes/emails/class-wcs-email-cancelled-subscription.php:29 -msgid "Subscription Cancelled" -msgstr "" - -#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out -#: includes/emails/class-wcs-email-cancelled-subscription.php:31 -msgctxt "default email subject for cancelled emails sent to the admin" -msgid "[%s] Subscription Cancelled" -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:143 -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:210 -#: includes/emails/class-wcs-email-expired-subscription.php:141 -#: includes/emails/class-wcs-email-on-hold-subscription.php:141 -msgctxt "an email notification" -msgid "Enable/Disable" -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:145 -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:212 -#: includes/emails/class-wcs-email-expired-subscription.php:143 -#: includes/emails/class-wcs-email-on-hold-subscription.php:143 -msgid "Enable this email notification" -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:149 -#: includes/emails/class-wcs-email-expired-subscription.php:147 -#: includes/emails/class-wcs-email-on-hold-subscription.php:147 -msgctxt "of an email" -msgid "Recipient(s)" -msgstr "" - -#. translators: placeholder is admin email -#: includes/emails/class-wcs-email-cancelled-subscription.php:152 -#: includes/emails/class-wcs-email-expired-subscription.php:150 -#: includes/emails/class-wcs-email-on-hold-subscription.php:150 -msgid "Enter recipients (comma separated) for this email. Defaults to %s." -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:157 -#: includes/emails/class-wcs-email-expired-subscription.php:155 -#: includes/emails/class-wcs-email-on-hold-subscription.php:155 -msgctxt "of an email" -msgid "Subject" -msgstr "" - -#. translators: %s: default e-mail subject. -#: includes/emails/class-wcs-email-cancelled-subscription.php:160 -#: includes/emails/class-wcs-email-expired-subscription.php:158 -#: includes/emails/class-wcs-email-on-hold-subscription.php:158 -msgid "This controls the email subject line. Leave blank to use the default subject: %s." -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:165 -#: includes/emails/class-wcs-email-expired-subscription.php:163 -#: includes/emails/class-wcs-email-on-hold-subscription.php:163 -msgctxt "Name the setting that controls the main heading contained within the email notification" -msgid "Email Heading" -msgstr "" - -#. translators: %s: default e-mail heading. -#: includes/emails/class-wcs-email-cancelled-subscription.php:168 -msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:173 -#: includes/emails/class-wcs-email-expired-subscription.php:171 -#: includes/emails/class-wcs-email-on-hold-subscription.php:171 -msgctxt "text, html or multipart" -msgid "Email type" -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:175 -#: includes/emails/class-wcs-email-expired-subscription.php:173 -#: includes/emails/class-wcs-email-on-hold-subscription.php:173 -msgid "Choose which format of email to send." -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:179 -#: includes/emails/class-wcs-email-expired-subscription.php:177 -#: includes/emails/class-wcs-email-on-hold-subscription.php:177 -msgctxt "email type" -msgid "Plain text" -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:180 -#: includes/emails/class-wcs-email-expired-subscription.php:178 -#: includes/emails/class-wcs-email-on-hold-subscription.php:178 -msgctxt "email type" -msgid "HTML" -msgstr "" - -#: includes/emails/class-wcs-email-cancelled-subscription.php:181 -#: includes/emails/class-wcs-email-expired-subscription.php:179 -#: includes/emails/class-wcs-email-on-hold-subscription.php:179 -msgctxt "email type" -msgid "Multipart" -msgstr "" - -#: includes/emails/class-wcs-email-completed-renewal-order.php:25 -msgid "Completed Renewal Order" -msgstr "" - -#: includes/emails/class-wcs-email-completed-renewal-order.php:26 -msgid "Renewal order complete emails are sent to the customer when a subscription renewal order is marked complete and usually indicates that the item for that renewal period has been shipped." -msgstr "" - -#: includes/emails/class-wcs-email-completed-renewal-order.php:29 -msgctxt "Default email heading for email to customer on completed renewal order" -msgid "Your renewal order is complete" -msgstr "" - -#. translators: $1: {blogname}, $2: {order_date}, variables that will be substituted when email is sent out -#: includes/emails/class-wcs-email-completed-renewal-order.php:31 -msgctxt "Default email subject for email to customer on completed renewal order" -msgid "Your %1$s renewal order from %2$s is complete" -msgstr "" - -#: includes/emails/class-wcs-email-completed-renewal-order.php:38 -msgctxt "Default email heading for email with downloadable files in it" -msgid "Your subscription renewal order is complete - download your files" -msgstr "" - -#. translators: $1: {blogname}, $2: {order_date}, variables will be substituted when email is sent out -#: includes/emails/class-wcs-email-completed-renewal-order.php:40 -msgctxt "Default email subject for email with downloadable files in it" -msgid "Your %1$s subscription renewal order from %2$s is complete - download your files" -msgstr "" - -#: includes/emails/class-wcs-email-completed-switch-order.php:26 -msgid "Subscription Switch Complete" -msgstr "" - -#: includes/emails/class-wcs-email-completed-switch-order.php:27 -msgid "Subscription switch complete emails are sent to the customer when a subscription is switched successfully." -msgstr "" - -#: includes/emails/class-wcs-email-completed-switch-order.php:30 -msgid "Your subscription change is complete" -msgstr "" - -#: includes/emails/class-wcs-email-completed-switch-order.php:31 -msgid "Your {blogname} subscription change from {order_date} is complete" -msgstr "" - -#: includes/emails/class-wcs-email-completed-switch-order.php:38 -msgid "Your subscription change is complete - download your files" -msgstr "" - -#: includes/emails/class-wcs-email-completed-switch-order.php:39 -msgid "Your {blogname} subscription change from {order_date} is complete - download your files" -msgstr "" - -#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:23 -msgid "On-hold Renewal Order" -msgstr "" - -#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:24 -msgid "This is an order notification sent to customers containing order details after a renewal order is placed on-hold." -msgstr "" - -#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:25 -msgid "Your {blogname} renewal order has been received!" -msgstr "" - -#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:26 -msgid "Thank you for your renewal order" -msgstr "" - -#: includes/emails/class-wcs-email-customer-payment-retry.php:24 -msgid "Customer Payment Retry" -msgstr "" - -#: includes/emails/class-wcs-email-customer-payment-retry.php:25 -msgid "Sent to a customer when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future. The email contains the renewal order information, date of the scheduled retry and payment links to allow the customer to pay for the renewal order manually instead of waiting for the automatic retry." -msgstr "" - -#: includes/emails/class-wcs-email-customer-payment-retry.php:32 -msgid "Automatic payment failed for {order_number}, we will retry {retry_time}" -msgstr "" - -#: includes/emails/class-wcs-email-customer-payment-retry.php:33 -msgid "Automatic payment failed for order {order_number}" -msgstr "" - -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:40 -msgid "Customer Renewal Invoice" -msgstr "" - -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:41 -msgid "Sent to a customer when the subscription is due for renewal and the renewal requires a manual payment, either because it uses manual renewals or the automatic recurring payment failed for the initial attempt and all automatic retries (if any). The email contains renewal order information and payment links." -msgstr "" - -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:48 -msgid "Invoice for renewal order {order_number} from {order_date}" -msgstr "" - -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:49 -msgid "Invoice for renewal order {order_number}" -msgstr "" - -#: includes/emails/class-wcs-email-expired-subscription.php:26 -msgid "Expired Subscription" -msgstr "" - -#: includes/emails/class-wcs-email-expired-subscription.php:27 -msgid "Expired Subscription emails are sent when a customer's subscription expires." -msgstr "" - -#: includes/emails/class-wcs-email-expired-subscription.php:29 -msgid "Subscription Expired" -msgstr "" - -#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out -#: includes/emails/class-wcs-email-expired-subscription.php:31 -msgctxt "default email subject for expired emails sent to the admin" -msgid "[%s] Subscription Expired" -msgstr "" - -#: includes/emails/class-wcs-email-expired-subscription.php:78 -#: includes/emails/class-wcs-email-on-hold-subscription.php:78 -msgid "Subscription argument passed in is not an object." -msgstr "" - -#. translators: %s: default e-mail heading. -#: includes/emails/class-wcs-email-expired-subscription.php:166 -#: includes/emails/class-wcs-email-on-hold-subscription.php:166 -msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." -msgstr "" - -#: includes/emails/class-wcs-email-new-renewal-order.php:22 -msgid "New Renewal Order" -msgstr "" - -#: includes/emails/class-wcs-email-new-renewal-order.php:23 -msgid "New renewal order emails are sent when a subscription renewal payment is processed." -msgstr "" - -#: includes/emails/class-wcs-email-new-renewal-order.php:25 -msgid "New subscription renewal order" -msgstr "" - -#: includes/emails/class-wcs-email-new-renewal-order.php:26 -msgid "[{blogname}] New subscription renewal order ({order_number}) - {order_date}" -msgstr "" - -#: includes/emails/class-wcs-email-new-switch-order.php:22 -#: includes/emails/class-wcs-email-new-switch-order.php:25 -msgid "Subscription Switched" -msgstr "" - -#: includes/emails/class-wcs-email-new-switch-order.php:23 -msgid "Subscription switched emails are sent when a customer switches a subscription." -msgstr "" - -#: includes/emails/class-wcs-email-new-switch-order.php:26 -msgid "[{blogname}] Subscription Switched ({order_number}) - {order_date}" -msgstr "" - -#: includes/emails/class-wcs-email-on-hold-subscription.php:26 -msgid "Suspended Subscription" -msgstr "" - -#: includes/emails/class-wcs-email-on-hold-subscription.php:27 -msgid "Suspended Subscription emails are sent when a customer manually suspends their subscription." -msgstr "" - -#: includes/emails/class-wcs-email-on-hold-subscription.php:29 -msgid "Subscription Suspended" -msgstr "" - -#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out -#: includes/emails/class-wcs-email-on-hold-subscription.php:31 -msgctxt "default email subject for suspended emails sent to the admin" -msgid "[%s] Subscription Suspended" -msgstr "" - -#: includes/emails/class-wcs-email-payment-retry.php:26 -msgid "Payment Retry" -msgstr "" - -#: includes/emails/class-wcs-email-payment-retry.php:27 -msgid "Payment retry emails are sent to chosen recipient(s) when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future." -msgstr "" - -#: includes/emails/class-wcs-email-payment-retry.php:29 -msgid "Automatic renewal payment failed" -msgstr "" - -#: includes/emails/class-wcs-email-payment-retry.php:30 -msgid "[{site_title}] Automatic payment failed for {order_number}, retry scheduled to run {retry_time}" -msgstr "" - -#: includes/emails/class-wcs-email-processing-renewal-order.php:24 -msgid "Processing Renewal order" -msgstr "" - -#: includes/emails/class-wcs-email-processing-renewal-order.php:25 -msgid "This is an order notification sent to the customer after payment for a subscription renewal order is completed. It contains the renewal order details." -msgstr "" - -#: includes/emails/class-wcs-email-processing-renewal-order.php:28 -msgid "Thank you for your order" -msgstr "" - -#: includes/emails/class-wcs-email-processing-renewal-order.php:29 -msgid "Your {blogname} renewal order receipt from {order_date}" -msgstr "" - -#. translators: 1-2: opening/closing tags - link to documentation. -#: includes/gateways/class-wc-subscriptions-payment-gateways.php:135 -msgid "Sorry, it seems there are no available payment methods which support subscriptions. Please see %1$sEnabling Payment Gateways for Subscriptions%2$s if you require assistance." -msgstr "" - -#: includes/gateways/class-wc-subscriptions-payment-gateways.php:137 -msgid "Sorry, it seems there are no available payment methods which support subscriptions. Please contact us if you require assistance or wish to make alternate arrangements." -msgstr "" - -#: includes/gateways/class-wc-subscriptions-payment-gateways.php:272 -msgid "Supported features:" -msgstr "" - -#: includes/gateways/class-wc-subscriptions-payment-gateways.php:275 -msgid "Subscription features:" -msgstr "" - -#: includes/gateways/class-wc-subscriptions-payment-gateways.php:279 -msgid "Change payment features:" -msgstr "" - -#: includes/gateways/paypal/class-wcs-paypal.php:220 -msgid "Unable to find order for PayPal billing agreement." -msgstr "" - -#: includes/gateways/paypal/class-wcs-paypal.php:282 -msgid "An error occurred, please try again or try an alternate form of payment." -msgstr "" - -#: includes/gateways/paypal/class-wcs-paypal.php:362 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:320 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:336 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:384 -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:150 -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:156 -msgctxt "hash before the order number. Used as a character to remove from the actual order number" -msgid "#" -msgstr "" - -#. translators: placeholders are PayPal API error code and PayPal API error message -#: includes/gateways/paypal/class-wcs-paypal.php:386 -msgid "PayPal API error: (%1$d) %2$s" -msgstr "" - -#. translators: placeholder is PayPal transaction status message -#: includes/gateways/paypal/class-wcs-paypal.php:391 -msgid "PayPal Transaction Held: %s" -msgstr "" - -#. translators: placeholder is PayPal transaction status message -#: includes/gateways/paypal/class-wcs-paypal.php:403 -msgid "PayPal payment declined: %s" -msgstr "" - -#. translators: placeholder is a transaction ID. -#: includes/gateways/paypal/class-wcs-paypal.php:407 -msgid "PayPal payment approved (ID: %s)" -msgstr "" - -#: includes/gateways/paypal/class-wcs-paypal.php:460 -msgid "" -"Are you sure you want to change the payment method from PayPal standard?\n" -"\n" -"This will suspend the subscription at PayPal." -msgstr "" - -#: includes/gateways/paypal/class-wcs-paypal.php:626 -msgctxt "used in User Agent data sent to PayPal to help identify where a payment came from" -msgid "WooCommerce Subscriptions PayPal" -msgstr "" - -#. translators: $1 and $2 are opening and closing strong tags, respectively. -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:63 -msgid "It is %1$sstrongly recommended you do not change the Receiver Email address%2$s if you have active subscriptions with PayPal. Doing so can break existing subscriptions." -msgstr "" - -#. translators: placeholders are opening and closing link tags. 1$-2$: to docs on woocommerce, 3$-4$ to gateway settings on the site -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:110 -msgid "PayPal is inactive for subscription transactions. Please %1$sset up the PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for Subscriptions." -msgstr "" - -#. translators: opening/closing tags - links to documentation. -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122 -msgid "%1$sPayPal Reference Transactions are not enabled on your account%2$s, some subscription management features are not enabled. Please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" -msgstr "" - -#. translators: opening/closing tags - links to documentation. -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:126 -msgid "%1$sPayPal Reference Transactions are not enabled on your account%2$s. If you wish to use PayPal Reference Transactions with Subscriptions, please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" -msgstr "" - -#. translators: placeholders are opening and closing strong tags. -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:148 -msgid "%1$sPayPal Reference Transactions are enabled on your account%2$s. All subscription management features are now enabled. Happy selling!" -msgstr "" - -#. translators: placeholders are link opening and closing tags. 1$-2$: to gateway settings, 3$-4$: support docs on woocommerce.com -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:159 -msgid "There is a problem with PayPal. Your API credentials may be incorrect. Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s." -msgstr "" - -#. translators: placeholders are opening and closing link tags. 1$-2$: docs on woocommerce, 3$-4$: dismiss link -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:172 -msgid "There is a problem with PayPal. Your PayPal account is issuing out-of-date subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." -msgstr "" - -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:194 -msgid "Ignore this error (not recommended)" -msgstr "" - -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:199 -msgid "Open a ticket" -msgstr "" - -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:286 -msgid "PayPal Subscription ID:" -msgstr "" - -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:312 -msgid "Enable PayPal Standard for Subscriptions" -msgstr "" - -#. translators: Placeholders are the opening and closing link tags. -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:320 -msgid "Before enabling PayPal Standard for Subscriptions, please note, when using PayPal Standard, customers are locked into using PayPal Standard for the life of their subscription, and PayPal Standard has a number of limitations. Please read the guide on %1$swhy we don't recommend PayPal Standard%2$s for Subscriptions before choosing to enable this option." -msgstr "" - -#. translators: placeholder is blogname -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:71 -msgctxt "data sent to paypal" -msgid "Orders with %s" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:279 -msgid "Total Discount" -msgstr "" - -#. translators: placeholder is blogname -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:306 -msgid "%s - Order" -msgstr "" - -#. translators: 1$: new status (e.g. "Cancel"), 2$: blog name -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:416 -msgctxt "data sent to paypal" -msgid "%1$s subscription event triggered at %2$s" -msgstr "" - -#. translators: %s: product SKU. -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:536 -msgid "SKU: %s" -msgstr "" - -#. translators: placeholder is localised datetime -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119 -msgid "expected clearing date %s" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:136 -msgctxt "used in api error message if there is no severity code from PayPal" -msgid "Error" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:138 -msgctxt "used in api error message if there is no long message" -msgid "Unknown error" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:150 -#: templates/admin/deprecated/order-shipping-html.php:14 -#: templates/admin/deprecated/order-tax-html.php:9 -msgctxt "no information about something" -msgid "N/A" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php:94 -msgid "Billing agreement cancelled at PayPal." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:275 -msgctxt "when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method" -msgid "IPN subscription payment method changed to PayPal." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:279 -msgid "IPN subscription sign up completed." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:332 -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:416 -msgid "IPN subscription payment completed." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:378 -msgid "IPN subscription failing payment method changed." -msgstr "" - -#. translators: placeholder is payment status (e.g. "completed") -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:426 -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:435 -msgctxt "used in order note" -msgid "IPN subscription payment %s." -msgstr "" - -#. translators: 1: payment status (e.g. "completed"), 2: pending reason. -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:439 -msgctxt "used in order note" -msgid "IPN subscription payment %1$s for reason: %2$s." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:468 -msgid "IPN subscription suspended." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:491 -msgid "IPN subscription cancelled." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:507 -msgid "IPN subscription payment failure." -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:645 -msgid "Invalid PayPal IPN Payload: unable to find matching subscription." -msgstr "" - -#. translators: 1$: subscription ID, 2$: names of items, comma separated -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:75 -msgctxt "item name sent to paypal" -msgid "Subscription %1$s - %2$s" -msgstr "" - -#. translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma separated -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:78 -msgctxt "item name sent to paypal" -msgid "Subscription %1$s (Order %2$s) - %3$s" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42 -msgid "Subscription cancelled with PayPal" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:53 -msgid "Subscription suspended with PayPal" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:66 -msgid "Subscription reactivated with PayPal" -msgstr "" - -#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:113 -msgid "PayPal API error - credentials are incorrect." -msgstr "" - -#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. -#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:18 -msgid "A fatal error has occurred while processing a recent subscription payment with PayPal. Please %1$sopen a new ticket at WooCommerce Support%3$s immediately to get this resolved. %2$sLearn more »%3$s" -msgstr "" - -#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. -#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:29 -msgid "To resolve this as quickly as possible, please create a %1$stemporary administrator account%3$s with the user email woologin@woocommerce.com and share the credentials with us via %2$sQuickForget.com%3$s." -msgstr "" - -#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:36 -msgid "Last recorded error:" -msgstr "" - -#. translators: $1 is the log file name. $2 and $3 are opening and closing link tags, respectively. -#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:46 -msgid "To see the full error, view the %1$s log file from the %2$sWooCommerce logs screen.%3$s." -msgstr "" - -#: includes/payment-retry/class-wcs-retry-admin.php:46 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:46 msgid "Automatic Failed Payment Retries" msgstr "" #. translators: %d: retry count. -#: includes/payment-retry/class-wcs-retry-admin.php:100 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:100 msgid "%d Pending Payment Retry" msgid_plural "%d Pending Payment Retries" msgstr[0] "" msgstr[1] "" #. translators: %d: retry count. -#: includes/payment-retry/class-wcs-retry-admin.php:104 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:104 msgid "%d Processing Payment Retry" msgid_plural "%d Processing Payment Retries" msgstr[0] "" msgstr[1] "" #. translators: %d: retry count. -#: includes/payment-retry/class-wcs-retry-admin.php:108 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:108 msgid "%d Failed Payment Retry" msgid_plural "%d Failed Payment Retries" msgstr[0] "" msgstr[1] "" #. translators: %d: retry count. -#: includes/payment-retry/class-wcs-retry-admin.php:112 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:112 msgid "%d Successful Payment Retry" msgid_plural "%d Successful Payment Retries" msgstr[0] "" msgstr[1] "" #. translators: %d: retry count. -#: includes/payment-retry/class-wcs-retry-admin.php:116 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:116 msgid "%d Cancelled Payment Retry" msgid_plural "%d Cancelled Payment Retries" msgstr[0] "" msgstr[1] "" -#: includes/payment-retry/class-wcs-retry-admin.php:144 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:144 msgid "Retry Failed Payments" msgstr "" -#: includes/payment-retry/class-wcs-retry-admin.php:145 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:145 msgid "Enable automatic retry of failed recurring payments" msgstr "" #. translators: 1,2: opening/closing link tags (to documentation). -#: includes/payment-retry/class-wcs-retry-admin.php:150 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:150 msgid "Attempt to recover recurring revenue that would otherwise be lost due to payment methods being declined only temporarily. %1$sLearn more%2$s." msgstr "" -#: includes/payment-retry/class-wcs-retry-admin.php:172 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:172 msgctxt "label for the system status page" msgid "Custom Retry Rules" msgstr "" -#: includes/payment-retry/class-wcs-retry-admin.php:180 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:180 msgctxt "label for the system status page" msgid "Custom Retry Rule Class" msgstr "" -#: includes/payment-retry/class-wcs-retry-admin.php:188 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:188 msgctxt "label for the system status page" msgid "Custom Raw Retry Rule" msgstr "" -#: includes/payment-retry/class-wcs-retry-admin.php:196 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:196 msgctxt "label for the system status page" msgid "Custom Retry Rule" msgstr "" -#: includes/payment-retry/class-wcs-retry-admin.php:204 +#: includes/payment-retry/admin/class-wcs-retry-admin.php:204 msgctxt "label for the system status page" msgid "Retries Migration Status" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:25 +#: includes/payment-retry/admin/html-retries-table.php:17 +msgid "Retry Date" +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:19 +msgid "Retry Status" +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:20 +msgid "The status of the automatic payment retry: pending means the retry will be processed in the future, failed means the payment was not successful when retried and completed means the payment succeeded when retried." +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:23 +msgid "Status of Order" +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:24 +msgid "The status applied to the order for the time between when the renewal payment failed or last retry occurred and when this retry was processed." +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:27 +msgid "Status of Subscription" +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:28 +msgid "The status applied to the subscription for the time between when the renewal payment failed or last retry occurred and when this retry was processed." +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:31 +msgid "Email" +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:32 +msgid "The email sent to the customer when the renewal payment or payment retry failed to notify them that the payment would be retried." +msgstr "" + +#. translators: php date format +#: includes/payment-retry/admin/html-retries-table.php:44 +msgctxt "post date" +msgid "Y/m/d g:i:s A" +msgstr "" + +#: includes/payment-retry/admin/html-retries-table.php:47 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-row.php:32 +msgid "Unpublished" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-manager.php:120 +msgctxt "table heading" +msgid "Renewal Payment Retry" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-manager.php:230 +msgctxt "used in order note as reason for why status changed" +msgid "Retry rule applied:" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-manager.php:268 +msgctxt "used in order note as reason for why status changed" +msgid "Retry rule reapplied:" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-manager.php:324 +msgctxt "used in order note as reason for why order status changed" +msgid "Subscription renewal payment retry:" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-manager.php:328 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Subscription renewal payment retry:" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-manager.php:344 +msgid "Payment retry attempted on renewal order with multiple related subscriptions with no payment method in common." +msgstr "" + +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:25 msgid "Payment retry posts store details about the automatic retry of failed renewal payments." msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:35 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:35 msgctxt "Post type name" msgid "Renewal Payment Retries" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:36 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:36 msgid "Renewal Payment Retry" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:37 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:37 msgctxt "Admin menu name" msgid "Renewal Payment Retries" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:38 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:38 msgid "Add" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:39 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:39 msgid "Add New Retry" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:41 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:40 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:138 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:229 +msgid "Edit" +msgstr "" + +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:41 msgid "Edit Retry" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:42 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:42 msgid "New Retry" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:43 -#: includes/payment-retry/class-wcs-retry-post-store.php:44 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:43 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:44 msgid "View Retry" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:45 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:45 msgid "Search Renewal Payment Retries" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:46 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:46 msgid "No retries found" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:47 +#: includes/payment-retry/data-stores/class-wcs-retry-post-store.php:47 msgid "No retries found in trash" msgstr "" -#. Translators: %s subscription number. -#: includes/privacy/class-wcs-privacy-erasers.php:71 -msgid "Removed personal data from subscription %s." +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:24 +msgid "Customer Payment Retry" msgstr "" -#. Translators: %s subscription number. -#: includes/privacy/class-wcs-privacy-erasers.php:75 -msgid "Personal data within subscription %s has been retained." +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:25 +msgid "Sent to a customer when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future. The email contains the renewal order information, date of the scheduled retry and payment links to allow the customer to pay for the renewal order manually instead of waiting for the automatic retry." msgstr "" -#: includes/privacy/class-wcs-privacy-erasers.php:189 -msgid "Personal data removed." +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:32 +msgid "Automatic payment failed for {order_number}, we will retry {retry_time}" msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:77 -msgid "Subscription Number" +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:33 +msgid "Automatic payment failed for order {order_number}" msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:78 -msgid "Created Date" +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:26 +msgid "Payment Retry" msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:79 -msgid "Recurring Total" +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:27 +msgid "Payment retry emails are sent to chosen recipient(s) when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future." msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:80 -msgid "Subscription Items" +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:29 +msgid "Automatic renewal payment failed" msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:81 -msgid "IP Address" +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:30 +msgid "[{site_title}] Automatic payment failed for {order_number}, retry scheduled to run {retry_time}" msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:82 -msgid "Browser User Agent" +#: includes/switching/class-wc-subscriptions-switcher.php:203 +msgid "You have a subscription to this product. Choosing a new subscription will replace your existing subscription." msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:83 -#: wcs-functions.php:284 -msgid "Billing Address" +#: includes/switching/class-wc-subscriptions-switcher.php:205 +msgid "Choose a new subscription." msgstr "" -#: includes/privacy/class-wcs-privacy-exporters.php:84 -#: wcs-functions.php:283 -msgid "Shipping Address" -msgstr "" - -#: includes/privacy/class-wcs-privacy-exporters.php:85 -msgid "Phone Number" -msgstr "" - -#: includes/privacy/class-wcs-privacy-exporters.php:86 -msgid "Email Address" -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:43 -#: includes/privacy/class-wcs-privacy.php:44 -msgid "Subscriptions Data" -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:92 -msgid "By using WooCommerce Subscriptions, you may be storing personal data and depending on which third-party payment processors you’re using to take subscription payments, you may be sharing personal data with external sources." -msgstr "" - -#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. -#: includes/privacy/class-wcs-privacy.php:94 -msgid "What we collect and store" -msgstr "" - -#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. -#: includes/privacy/class-wcs-privacy.php:95 -msgid "For the purposes of processing recurring subscription payments, we store the customer's name, billing address, shipping address, email address, phone number and credit card/payment details." -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:96 -msgid "What we share with others" -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:97 -msgid "What personal information your store shares with external sources depends on which third-party payment processor plugins you are using to collect subscription payments. We recommend that you consult with their privacy policies to inform this section of your privacy policy." -msgstr "" - -#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. -#: includes/privacy/class-wcs-privacy.php:99 -msgid "If you are using PayPal Standard or PayPal Reference transactions please see the %1$sPayPal Privacy Policy%2$s for more details." -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:109 -msgid "Cancel and remove personal data" -msgstr "" - -#. translators: %d: number of subscriptions affected. -#: includes/privacy/class-wcs-privacy.php:176 -msgid "Removed personal data from %d subscription." -msgid_plural "Removed personal data from %d subscriptions." +#: includes/switching/class-wc-subscriptions-switcher.php:245 +#: includes/switching/class-wc-subscriptions-switcher.php:1219 +msgid "Your cart contained an invalid subscription switch request. It has been removed." +msgid_plural "Your cart contained invalid subscription switch requests. They have been removed." msgstr[0] "" msgstr[1] "" -#. translators: placeholders are opening and closing tags. -#: includes/privacy/class-wcs-privacy.php:195 -msgid "%1$sNote:%2$s Orders which are related to subscriptions will not be included in the orders affected by these settings." +#: includes/switching/class-wc-subscriptions-switcher.php:287 +msgid "You have already subscribed to this product and it is limited to one per customer. You can not purchase the product again." msgstr "" -#: includes/privacy/class-wcs-privacy.php:215 -msgid "account erasure request" +#. translators: 1$: is the "You have already subscribed to this product" notice, 2$-4$: opening/closing link tags, 3$: an order number +#: includes/switching/class-wc-subscriptions-switcher.php:296 +msgid "%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your subscription." msgstr "" -#: includes/privacy/class-wcs-privacy.php:221 -msgid "Remove personal data from subscriptions" -msgstr "" - -#. Translators: %s URL to erasure request screen. -#: includes/privacy/class-wcs-privacy.php:223 -msgid "When handling an %s, should personal data within subscriptions be retained or removed?" -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:232 -msgid "Retain ended subscriptions" -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:233 -msgid "Retain ended subscriptions and their related orders for a specified duration before anonymizing the personal data within them." -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:236 -msgid "N/A" -msgstr "" - -#: includes/privacy/class-wcs-privacy.php:277 -msgid "Customers with a subscription are excluded from this setting." -msgstr "" - -#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 & 1.5") -#: includes/upgrades/class-wc-subscriptions-upgrader.php:337 -msgid "Database updated to version %s" -msgstr "" - -#. translators: placeholder is number of upgraded subscriptions -#: includes/upgrades/class-wc-subscriptions-upgrader.php:345 -msgctxt "used in the subscriptions upgrader" -msgid "Marked %s subscription products as \"sold individually\"." -msgstr "" - -#. translators: 1$: number of action scheduler hooks upgraded, 2$: "{execution_time}", will be replaced on front end with actual time -#: includes/upgrades/class-wc-subscriptions-upgrader.php:354 -msgid "Migrated %1$s subscription related hooks to the new scheduler (in %2$s seconds)." -msgstr "" - -#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}", will be replaced on front end with actual time it took -#: includes/upgrades/class-wc-subscriptions-upgrader.php:366 -msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)." -msgstr "" - -#. translators: placeholder is "{time_left}", will be replaced on front end with actual time -#: includes/upgrades/class-wc-subscriptions-upgrader.php:369 -#: includes/upgrades/class-wc-subscriptions-upgrader.php:415 -msgctxt "Message that gets sent to front end." -msgid "Estimated time left (minutes:seconds): %s" -msgstr "" - -#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, 4$: break tag -#: includes/upgrades/class-wc-subscriptions-upgrader.php:379 -msgid "Unable to upgrade subscriptions.%4$sError: %1$s%4$sPlease refresh the page and try again. If problem persists, %2$scontact support%3$s." -msgstr "" - -#. translators: placeholder is the number of subscriptions repaired -#: includes/upgrades/class-wc-subscriptions-upgrader.php:394 -msgctxt "Repair message that gets sent to front end." -msgid "Repaired %d subscriptions with incorrect dates, line tax data or missing customer notes." -msgstr "" - -#. translators: placeholder is number of subscriptions that were checked and did not need repairs. There's a space at the beginning! -#: includes/upgrades/class-wc-subscriptions-upgrader.php:400 -msgctxt "Repair message that gets sent to front end." -msgid " %d other subscription was checked and did not need any repairs." -msgid_plural "%d other subscriptions were checked and did not need any repairs." -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is "{execution_time}", which will be replaced on front end with actual time -#: includes/upgrades/class-wc-subscriptions-upgrader.php:404 -msgctxt "Repair message that gets sent to front end." -msgid "(in %s seconds)" -msgstr "" - -#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL languages. -#: includes/upgrades/class-wc-subscriptions-upgrader.php:407 -msgctxt "The assembled repair message that gets sent to front end." -msgid "%1$s%2$s %3$s" -msgstr "" - -#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, 4$: break tag -#: includes/upgrades/class-wc-subscriptions-upgrader.php:426 -msgctxt "Error message that gets sent to front end when upgrading Subscriptions" -msgid "Unable to repair subscriptions.%4$sError: %1$s%4$sPlease refresh the page and try again. If problem persists, %2$scontact support%3$s." -msgstr "" - -#: includes/upgrades/class-wc-subscriptions-upgrader.php:630 -msgid "Welcome to WooCommerce Subscriptions 2.1" -msgstr "" - -#: includes/upgrades/class-wc-subscriptions-upgrader.php:630 -msgid "About WooCommerce Subscriptions" -msgstr "" - -#. translators: 1-2: opening/closing tags, 3: active version of Subscriptions, 4: current version of Subscriptions, 5-6: opening/closing tags linked to ticket form, 7-8: opening/closing tags linked to documentation. -#: includes/upgrades/class-wc-subscriptions-upgrader.php:812 -msgid "%1$sWarning!%2$s It appears that you have downgraded %1$sWooCommerce Subscriptions%2$s from %3$s to %4$s. Downgrading the plugin in this way may cause issues. Please update to %3$s or higher, or %5$sopen a new support ticket%6$s for further assistance. %7$sLearn more »%8$s" -msgstr "" - -#. translators: 1-2: opening/closing tags, 3-4: opening/closing tags linked to ticket form. -#: includes/upgrades/class-wc-subscriptions-upgrader.php:885 -msgid "%1$sWarning!%2$s We discovered an issue in %1$sWooCommerce Subscriptions 2.3.0 - 2.3.2%2$s that may cause your subscription renewal order and customer subscription caches to contain invalid data. For information about how to update the cached data, please %3$sopen a new support ticket%4$s." -msgstr "" - -#: includes/upgrades/class-wcs-repair-suspended-paypal-subscriptions.php:51 -msgid "Subscription suspended by Database repair script. This subscription was suspended via PayPal." -msgstr "" - -#: includes/upgrades/class-wcs-upgrade-2-2-7.php:60 -msgid "Subscription end date in the past" -msgstr "" - -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:80 -msgctxt "plugin version number used in admin notice" -msgid "3.0" -msgstr "" - -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:85 -msgid "Improved scheduled action data storage" -msgstr "" - -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:86 -msgid "Scheduled action data, which was previously stored in the WordPress post tables, has been moved to a custom database table. Amongst other benefits, this will greatly improve the performance of processing scheduled actions such as subscription payments." -msgstr "" - -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:89 -msgid "Increased processing rate for scheduled payments" -msgstr "" - -#. translators: 1-2: opening/closing tags - link to documentation. -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:92 -msgid "Previous versions of Subscriptions relied on %1$sWP Cron%2$s to process subscription payments and other scheduled events. In 3.0, these events will now run on admin request with loopback support. This will significantly increase the throughput of payment processing." -msgstr "" - -#. translators: placeholder is Subscription version string ('2.3') -#: includes/upgrades/class-wcs-upgrade-notice-manager.php:99 -msgid "Welcome to WooCommerce Subscriptions %s!" -msgstr "" - -#. translators: placeholder is Subscription version string ('2.3') -#: includes/upgrades/templates/update-welcome-notice.php:2 -#: includes/upgrades/templates/wcs-about-2-0.php:23 -#: includes/upgrades/templates/wcs-about.php:22 -msgid "Thank you for updating to the latest version of WooCommerce Subscriptions." -msgstr "" - -#. translators: placeholder $1 is the Subscription version string ('2.3'), $2-3 are opening and closing tags -#: includes/upgrades/templates/update-welcome-notice.php:5 -msgid "Version %1$s brings some new improvements requested by store managers just like you (and possibly even by %2$syou%3$s)." -msgstr "" - -#: includes/upgrades/templates/update-welcome-notice.php:6 -#: includes/upgrades/templates/wcs-about-2-0.php:25 -#: includes/upgrades/templates/wcs-about.php:24 -msgid "We hope you enjoy it!" -msgstr "" - -#: includes/upgrades/templates/update-welcome-notice.php:8 -msgid "What's new?" -msgstr "" - -#. translators: placeholder is Subscription version string ('2.3') -#: includes/upgrades/templates/update-welcome-notice.php:16 -msgid "Want to know more about Subscriptions %s?" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:20 -msgid "Welcome to Subscriptions 2.0" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:24 -msgid "Version 2.0 has been in development for more than a year. We've reinvented the extension to take into account 3 years of feedback from store managers." -msgstr "" - -#. translators: placeholder is version number -#: includes/upgrades/templates/wcs-about-2-0.php:31 -#: includes/upgrades/templates/wcs-about.php:30 -msgid "Version %s" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:36 -#: woocommerce-subscriptions.php:1146 -msgctxt "short for documents" -msgid "Docs" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:42 -#: includes/upgrades/templates/wcs-about.php:41 -msgid "Check Out What's New" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:51 -msgid "Multiple Subscriptions" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:52 -msgid "It's now easier for your customers to buy more subscriptions!" -msgstr "" - -#: includes/upgrades/templates/wcs-about-2-0.php:53 -msgid "Customers can now purchase different subscription products in one transaction. The products can bill on any schedule and have any combination of sign-up fees and/or free trials." +#: includes/switching/class-wc-subscriptions-switcher.php:390 +msgid "Switching" msgstr "" #. translators: placeholders are opening and closing link tags -#: includes/upgrades/templates/wcs-about-2-0.php:56 -msgid "Learn more about the new %smultiple subscriptions%s feature." +#: includes/switching/class-wc-subscriptions-switcher.php:393 +msgid "Allow subscribers to switch (upgrade or downgrade) between different subscriptions. %1$sLearn more%2$s." msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:68 -msgid "New Add/Edit Subscription Screen" +#: includes/switching/class-wc-subscriptions-switcher.php:401 +msgid "Prorate Recurring Payment" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:69 -msgid "Subscriptions v2.0 introduces a new administration interface to add or edit a subscription. You can make all the familiar changes, like modifying recurring totals or subscription status. You can also make some new modifications, like changing the expiration date, adding a shipping cost or adding a product line item." +#: includes/switching/class-wc-subscriptions-switcher.php:402 +msgid "When switching to a subscription with a different recurring payment or billing period, should the price paid for the existing billing period be prorated when switching to the new subscription?" msgstr "" -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about-2-0.php:72 -msgid "The new interface is also built on the existing %sEdit Order%s screen. If you've ever modified an order, you already know how to modify a subscription." +#: includes/switching/class-wc-subscriptions-switcher.php:409 +#: includes/switching/class-wc-subscriptions-switcher.php:441 +msgctxt "when to allow a setting" +msgid "Never" msgstr "" -#. translators: placeholers are link tags: 1$-2$ new subscription page, 3$-4$: docs on woocommerce.com -#: includes/upgrades/templates/wcs-about-2-0.php:76 -msgid "%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new interface." +#: includes/switching/class-wc-subscriptions-switcher.php:410 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of Virtual Subscription Products Only" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:87 -msgid "New View Subscription Page" +#: includes/switching/class-wc-subscriptions-switcher.php:411 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of All Subscription Products" msgstr "" -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about-2-0.php:91 -msgid "Your customers can now view the full details of a subscription, including line items, billing and shipping address, billing schedule and renewal orders, from a special %sMy Account > View Subscription%s page." +#: includes/switching/class-wc-subscriptions-switcher.php:412 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of Virtual Subscription Products Only" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:93 -msgid "This new page is also where the customer can suspend or cancel their subscription, change payment method, change shipping address or upgrade/downgrade an item." +#: includes/switching/class-wc-subscriptions-switcher.php:413 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of All Subscription Products" msgstr "" -#. translators: placeholders are opening and closing link tags -#: includes/upgrades/templates/wcs-about-2-0.php:97 -msgid "Learn more about the new %sView Subscription page%s." +#: includes/switching/class-wc-subscriptions-switcher.php:418 +msgid "Prorate Sign up Fee" msgstr "" -#. translators: placeholders are for opening and closing link () tags -#: includes/upgrades/templates/wcs-about-2-0.php:111 -msgid "By default, adding new files to an existing subscription product will automatically provide active subscribers with access to the new files. However, now you can enable a %snew content dripping setting%s to provide subscribers with access to new files only after the next renewal payment." +#: includes/switching/class-wc-subscriptions-switcher.php:419 +msgid "When switching to a subscription with a sign up fee, you can require the customer pay only the gap between the existing subscription's sign up fee and the new subscription's sign up fee (if any)." msgstr "" -#. translators: placeholders are for opening and closing link () tags -#. translators: placeholders are opening and closing anchor tags linking to documentation -#: includes/upgrades/templates/wcs-about-2-0.php:115 -#: includes/upgrades/templates/wcs-about-2-0.php:128 -#: includes/upgrades/templates/wcs-about-2-0.php:141 -#: includes/upgrades/templates/wcs-about.php:120 -#: includes/upgrades/templates/wcs-about.php:131 -#: includes/upgrades/templates/wcs-about.php:142 -#: includes/upgrades/templates/wcs-about.php:170 -#: includes/upgrades/templates/wcs-about.php:191 -msgid "%sLearn more »%s" +#: includes/switching/class-wc-subscriptions-switcher.php:426 +msgctxt "when to prorate signup fee when switching" +msgid "Never (do not charge a sign up fee)" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:121 -msgctxt "h3 on the About Subscriptions page for this new feature" -msgid "Change Payment Method" +#: includes/switching/class-wc-subscriptions-switcher.php:427 +msgctxt "when to prorate signup fee when switching" +msgid "Never (charge the full sign up fee)" msgstr "" -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about-2-0.php:124 -msgid "For a store manager to change a subscription from automatic to manual renewal payments (or manual to automatic) with Subscriptions v1.5, the database needed to be modified directly. Subscriptions now provides a way for payment gateways to allow you to change that from the new %sEdit Subscription%s interface." +#: includes/switching/class-wc-subscriptions-switcher.php:428 +msgctxt "when to prorate signup fee when switching" +msgid "Always" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:134 -msgid "Change Trial and End Dates" +#: includes/switching/class-wc-subscriptions-switcher.php:433 +msgid "Prorate Subscription Length" msgstr "" -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about-2-0.php:137 -msgid "It was already possible to change a subscription's next payment date, but some store managers wanted to provide a customer with an extended free trial or add an extra month to the expiration date. Now you can change all of these dates from the %sEdit Subscription%s screen." +#: includes/switching/class-wc-subscriptions-switcher.php:434 +msgid "When switching to a subscription with a length, you can take into account the payments already completed by the customer when determining how many payments the subscriber needs to make for the new subscription." msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:150 -msgid "And much more..." +#: includes/switching/class-wc-subscriptions-switcher.php:442 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:224 +msgctxt "when to prorate first payment / subscription length" +msgid "For Virtual Subscription Products Only" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:157 -#: includes/upgrades/templates/wcs-about.php:151 -msgid "Peek Under the Hood for Developers" +#: includes/switching/class-wc-subscriptions-switcher.php:443 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:225 +msgctxt "when to prorate first payment / subscription length" +msgid "For All Subscription Products" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:158 -msgid "Subscriptions 2.0 introduces a new architecture built on the WooCommerce Custom Order Types API." +#: includes/switching/class-wc-subscriptions-switcher.php:448 +msgid "Switch Button Text" msgstr "" -#. translators: placeholders are opening and closing code tags -#: includes/upgrades/templates/wcs-about-2-0.php:164 -msgid "New %sshop_subscription%s Post Type" +#: includes/switching/class-wc-subscriptions-switcher.php:449 +msgid "Customise the text displayed on the button next to the subscription on the subscriber's account page. The default is \"Switch Subscription\", but you may wish to change this to \"Upgrade\" or \"Change Subscription\"." msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:166 -msgid "By making a subscription a Custom Order Type, a subscription is also now a custom post type. This makes it faster to query subscriptions and it uses a database schema that is as scalable as WordPress posts and pages." +#: includes/switching/class-wc-subscriptions-switcher.php:453 +#: includes/switching/class-wc-subscriptions-switcher.php:555 +#: includes/switching/class-wc-subscriptions-switcher.php:2599 +msgid "Upgrade or Downgrade" msgstr "" -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about-2-0.php:169 -msgid "Developers can also now use all the familiar WordPress functions, like %sget_posts()%s, to query or modify subscription data." +#: includes/switching/class-wc-subscriptions-switcher.php:492 +msgid "Allow Switching" msgstr "" -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about-2-0.php:175 -msgid "New %sWC_Subscription%s Object" +#: includes/switching/class-wc-subscriptions-switcher.php:499 +msgctxt "when to allow switching" +msgid "Between Subscription Variations" msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:177 -msgid "Subscriptions 2.0 introduces a new object for working with a subscription at the application level. The cumbersome APIs for retrieving or modifying a subscription's data are gone!" +#: includes/switching/class-wc-subscriptions-switcher.php:503 +msgctxt "when to allow switching" +msgid "Between Grouped Subscriptions" msgstr "" -#. translators: all placeholders are opening and closing tags, no need to order them -#: includes/upgrades/templates/wcs-about-2-0.php:180 -msgid "Because the %sWC_Subscription%s class extends %sWC_Order%s, you can use its familiar methods, like %s$subscription->update_status()%s or %s$subscription->get_total()%s." +#. translators: %s: order number. +#: includes/switching/class-wc-subscriptions-switcher.php:1142 +msgid "Switch order cancelled due to a new switch order being created #%s." msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:184 -msgid "REST API Endpoints" +#: includes/switching/class-wc-subscriptions-switcher.php:1347 +msgid "You can only switch to a subscription product." msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:185 -msgid "We didn't just improve interfaces for humans, we also improved them for computers. Your applications can now create, read, update or delete subscriptions via RESTful API endpoints." +#: includes/switching/class-wc-subscriptions-switcher.php:1353 +msgid "We can not find your old subscription item." msgstr "" -#. translators: all placeholders are opening and closing tags, no need to order them -#: includes/upgrades/templates/wcs-about-2-0.php:188 -msgid "Want to list all the subscriptions on a site? Get %sexample.com/wc-api/v2/subscriptions/%s. Want the details of a specific subscription? Get %s/wc-api/v2/subscriptions//%s." +#: includes/switching/class-wc-subscriptions-switcher.php:1375 +msgid "You can not switch to the same subscription." msgstr "" -#: includes/upgrades/templates/wcs-about-2-0.php:194 -msgid "Go to WooCommerce Subscriptions Settings" +#: includes/switching/class-wc-subscriptions-switcher.php:1422 +msgid "You can not switch this subscription. It appears you do not own the subscription." msgstr "" -#: includes/upgrades/templates/wcs-about.php:19 -msgid "Welcome to Subscriptions 2.1!" +#: includes/switching/class-wc-subscriptions-switcher.php:1463 +msgid "There was an error locating the switch details." msgstr "" -#: includes/upgrades/templates/wcs-about.php:23 -msgid "Version 2.1 introduces some great new features requested by store managers just like you (and possibly even by %syou%s)." +#: includes/switching/class-wc-subscriptions-switcher.php:1825 +msgctxt "a switch type" +msgid "Downgrade" msgstr "" -#: includes/upgrades/templates/wcs-about.php:35 -msgctxt "short for documents" -msgid "Documentation" +#: includes/switching/class-wc-subscriptions-switcher.php:1828 +msgctxt "a switch type" +msgid "Upgrade" msgstr "" -#: includes/upgrades/templates/wcs-about.php:49 -msgid "Subscription Reports" +#: includes/switching/class-wc-subscriptions-switcher.php:1831 +msgctxt "a switch type" +msgid "Crossgrade" msgstr "" -#: includes/upgrades/templates/wcs-about.php:50 -msgid "How many customers stay subscribed for more than 6 months? What is the average lifetime value of your subscribers? How much renewal revenue will your store earn next month?" +#. translators: %1: product subtotal, %2: HTML span tag, %3: direction (upgrade, downgrade, crossgrade), %4: closing HTML span tag +#: includes/switching/class-wc-subscriptions-switcher.php:1836 +msgctxt "product subtotal string" +msgid "%1$s %2$s(%3$s)%4$s" msgstr "" -#: includes/upgrades/templates/wcs-about.php:51 -msgid "These are important questions for any subscription commerce business." +#: includes/switching/class-wc-subscriptions-switcher.php:1952 +msgid "The original subscription item being switched cannot be found." msgstr "" -#: includes/upgrades/templates/wcs-about.php:52 -msgid "Prior to Subscriptions 2.1, they were not easy to answer. Subscriptions 2.1 introduces new reports to answer these questions, and many more." +#: includes/switching/class-wc-subscriptions-switcher.php:1954 +msgid "The item on the switch order cannot be found." msgstr "" -#: includes/upgrades/templates/wcs-about.php:54 -msgid "View Reports" +#. translators: 1$: old item, 2$: new item when switching +#: includes/switching/class-wc-subscriptions-switcher.php:1965 +msgctxt "used in order notes" +msgid "Customer switched from: %1$s to %2$s." msgstr "" -#: includes/upgrades/templates/wcs-about.php:55 -msgctxt "learn more link to subscription reports documentation" -msgid "Learn More" +#. translators: %s: new item name. +#: includes/switching/class-wc-subscriptions-switcher.php:1968 +msgctxt "used in order notes" +msgid "Customer added %s." msgstr "" -#: includes/upgrades/templates/wcs-about.php:67 -msgid "Automatic Failed Payment Retry" +#: includes/switching/class-wc-subscriptions-switcher.php:2323 +#: includes/switching/class-wc-subscriptions-switcher.php:2876 +msgid "Switch Order" msgstr "" -#: includes/upgrades/templates/wcs-about.php:68 -msgid "Failed recurring payments can now be retried automatically. This helps recover revenue that would otherwise be lost due to payment methods being declined only temporarily." +#: includes/switching/class-wc-subscriptions-switcher.php:2338 +#: includes/switching/class-wc-subscriptions-switcher.php:2891 +msgid "Switched Subscription" msgstr "" -#: includes/upgrades/templates/wcs-about.php:69 -msgid "By default, Subscriptions will retry the payment 5 times over 7 days. The rules that control the retry system can be modified to customise:" +#: includes/switching/class-wc-subscriptions-switcher.php:2556 +msgctxt "add to cart button text while switching a subscription" +msgid "Switch subscription" msgstr "" -#: includes/upgrades/templates/wcs-about.php:71 -msgid "the total number of retry attempts" +#: includes/switching/class-wc-subscriptions-switcher.php:2740 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:233 +msgctxt "Subscription status" +msgid "Switched" msgstr "" -#: includes/upgrades/templates/wcs-about.php:72 -msgid "how long to wait between retry attempts" +#: includes/switching/class-wcs-cart-switch.php:180 +msgctxt "The place order button text while switching a subscription" +msgid "Switch subscription" msgstr "" -#: includes/upgrades/templates/wcs-about.php:73 -msgid "emails sent to the customer and store manager" +#. translators: placeholder is a switch type. +#: includes/switching/class-wcs-switch-cart-item.php:309 +msgid "Invalid switch type \"%s\". Switch must be one of: \"upgrade\", \"downgrade\" or \"crossgrade\"." msgstr "" -#: includes/upgrades/templates/wcs-about.php:74 -msgid "the status applied to the renewal order and subscription" +#: includes/switching/class-wcs-switch-totals-calculator.php:196 +msgid "Your cart contained an invalid subscription switch request. It has been removed from your cart." msgstr "" -#: includes/upgrades/templates/wcs-about.php:76 -msgid "The retry system is disabled by default. To enable it, visit the Subscriptions settings administration screen." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:78 -msgid "Enable Automatic Retry" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:79 -msgctxt "learn more link to failed payment retry documentation" -msgid "Learn More" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:90 -msgid "New Subscription Emails" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:91 -msgid "Subscriptions 2.1 also introduces a number of new emails to notify you when:" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:93 -msgid "a customer suspends a subscription" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:94 -msgid "an automatic payment fails" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:95 -msgid "a subscription expires" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:97 -msgid "These emails can be enabled, disabled and customised under the %sWooCommerce > Settings > Emails%s administration screen." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:99 -msgid "View Email Settings" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:100 -msgctxt "learn more link to subscription emails documentation" -msgid "Learn More" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:108 -msgid "But wait, there's more!" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:109 -msgid "That's not all we've working on for the last 12 months when it comes to Subscriptions. We've also released mini-extensions to help you get the most from your subscription store." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:115 -msgid "Subscription Gifting" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:116 -msgid "What happens when a customer wants to purchase a subscription product for someone else?" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:117 -msgid "The Gifting extension makes it possible for one person to purchase a subscription product for someone else. It then shares control of the subscription between the purchaser and recipient, allowing both to manage the subscription over its lifecycle." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:126 -msgctxt "h3 on the About Subscriptions page for this new feature" -msgid "Import/Export Subscriptions" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:127 -msgid "Import subscriptions to WooCommerce via CSV, or export your subscriptions from WooCommerce to a CSV with the WooCommerce Subscriptions Importer/Exporter extension." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:128 -msgid "This free extension makes it possible to migrate subscribers from 3rd party systems to WooCommerce. It also makes it possible to export your subscription data for analysis in spreadsheet tools or 3rd party apps." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:137 -msgid "Subscribe All the Things" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:138 -msgid "Want your customers to be able to subscribe to non-subscription products?" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:139 -msgid "With WooCommerce Subscribe All the Things, they can! This experimental extension is exploring how to convert any product, including Product Bundles and Composite Products, into a subscription product. It also offers customers a way to subscribe to a cart of non-subscription products." -msgstr "" - -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about.php:157 -msgid "Customise Retry Rules" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:159 -msgid "The best part about the new automatic retry system is that the retry rules are completely customisable." -msgstr "" - -#. translators: all placeholders are opening and closing tags, no need to order them -#: includes/upgrades/templates/wcs-about.php:162 -msgid "With the %s'wcs_default_retry_rules'%s filter, you can define a set of default rules to apply to all failed payments in your store." -msgstr "" - -#. translators: all placeholders are opening and closing tags, no need to order them -#: includes/upgrades/templates/wcs-about.php:166 -msgid "To apply a specific rule based on certain conditions, like high value orders or an infrequent renewal schedule, you can use the retry specific %s'wcs_get_retry_rule'%s filter. This provides the ID of the renewal order for the failed payment, which can be used to find information about the products, subscription and totals to which the failed payment relates." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:174 -msgid "WP REST API Endpoints" -msgstr "" - -#. translators: $1: opening tag linking to WC API docs, $2: closing tag, $3: opening tag linking to WP API docs, $4: closing tag -#: includes/upgrades/templates/wcs-about.php:177 -msgid "WooCommerce 2.6 added support for %1$sREST API%2$s endpoints built on WordPress core's %3$sREST API%4$s infrastructure." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:179 -msgid "Subscriptions 2.1 adds support for subscription data to this infrastructure." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:180 -msgid "Your applications can now create, read, update or delete subscriptions via RESTful API endpoints with the same design as the latest version of WooCommerce's REST API endpoints." -msgstr "" - -#. translators: all placeholders are opening and closing tags, no need to order them -#: includes/upgrades/templates/wcs-about.php:183 -msgid "Want to list all the subscriptions on a site? Get %s/wp-json/wc/v1/subscriptions%s." -msgstr "" - -#. translators: all placeholders are opening and closing tags, no need to order them -#: includes/upgrades/templates/wcs-about.php:187 -msgid "Want the details of a specific subscription? Get %s/wp-json/wc/v1/subscriptions//%s." -msgstr "" - -#. translators: placeholders are opening and closing code tags -#: includes/upgrades/templates/wcs-about.php:197 -msgid "Honour Renewal Order Data" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:199 -msgid "In previous versions of Subscriptions, the subscription total was passed to payment gateways as the amount to charge for automatic renewal payments. This made it unnecessarily complicated to add one-time fees or discounts to a renewal." -msgstr "" - -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about.php:202 -msgid "Subscriptions 2.1 now passes the renewal order's total, making it possible to add a fee or discount to the renewal order with simple one-liners like %s$order->add_fee()%s or %s$order->add_coupon()%s." -msgstr "" - -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-about.php:206 -msgid "Subscriptions also now uses the renewal order to setup the cart for %smanual renewals%s, making it easier to add products or discounts to a single renewal paid manually." -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:212 -msgid "See the full guide to What's New in Subscriptions version 2.1 »" -msgstr "" - -#: includes/upgrades/templates/wcs-about.php:213 -msgid "Go to WooCommerce Subscriptions Settings »" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade-in-progress.php:24 -msgid "WooCommerce Subscriptions Update in Progress" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade-in-progress.php:30 -msgid "The Upgrade is in Progress" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade-in-progress.php:31 -msgid "The WooCommerce Subscriptions plugin is currently running its database upgrade routine." -msgstr "" - -#. translators: placeholder is number of seconds -#: includes/upgrades/templates/wcs-upgrade-in-progress.php:34 -msgid "If you received a server error and reloaded the page to find this notice, please refresh the page in %s seconds and the upgrade routine will recommence without issues." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade-in-progress.php:36 -msgid "Rest assured, although the update process may take a little while, it is coded to prevent defects, your site is safe and will be up and running again, faster than ever, shortly." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:19 -msgid "WooCommerce Subscriptions Update" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:29 -msgid "Database Update Required" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:30 -msgid "The WooCommerce Subscriptions plugin has been updated!" -msgstr "" - -#. translators: placeholders are opening and closing tags -#: includes/upgrades/templates/wcs-upgrade.php:33 -msgid "Before we send you on your way, we need to update your database to the newest version. If you do not have a recent backup of your site, %snow is the time to create one%s." -msgstr "" - -#. translators: 1$: number of subscriptions on site, 2$, lower estimate (minutes), 3$: upper estimate -#: includes/upgrades/templates/wcs-upgrade.php:38 -msgid "The full update process for the %1$d subscriptions on your site will take between %2$d and %3$d minutes." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:41 -msgid "The update process may take a little while, so please be patient." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:43 -msgid "Customers and other non-administrative users can browse and purchase from your store without interruption while the update is in progress." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:45 -msgctxt "text on submit button" -msgid "Update Database" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:49 -msgid "Update in Progress" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:50 -msgid "This page will display the results of the process as each batch of subscriptions is updated." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:51 -msgid "Please keep this page open until the update process completes. No need to refresh or restart the process." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:53 -msgid "Remember, although the update process may take a while, customers and other non-administrative users can browse and purchase from your store without interruption while the update is in progress." -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:61 -msgid "Update Complete" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:62 -msgid "Your database has been updated successfully!" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:63 -msgid "Continue" -msgstr "" - -#. translators: $1: placeholder is number of weeks, 2$: path to the file -#: includes/upgrades/templates/wcs-upgrade.php:66 -msgid "To record the progress of the update a new log file was created. This file will be automatically deleted in %1$d weeks. If you would like to delete it sooner, you can find it here: %2$s" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:71 -msgid "Update Error" -msgstr "" - -#: includes/upgrades/templates/wcs-upgrade.php:72 -msgid "There was an error with the update. Please refresh the page and try again." -msgstr "" - -#. translators: %s: shipping method label. -#: includes/wcs-cart-functions.php:97 -#: includes/wcs-cart-functions.php:102 -msgid "Shipping via %s" -msgstr "" - -#: includes/wcs-cart-functions.php:227 -msgctxt "shipping method price" -msgid "Free" -msgstr "" - -#: includes/wcs-cart-functions.php:252 -msgid "[Remove]" -msgstr "" - -#: includes/wcs-cart-functions.php:282 -msgid "Free shipping coupon" -msgstr "" - -#. translators: placeholder is price string, denotes tax included in cart/order total -#: includes/wcs-cart-functions.php:320 -msgctxt "includes tax" -msgid "(includes %s)" -msgstr "" - -#. translators: placeholder is a date -#: includes/wcs-cart-functions.php:389 -#: tests/unit/wcs_test_wcs_cart_functions.php:225 -msgid "First renewal: %s" -msgstr "" - -#. translators: placeholder is either subscription key or a subscription id, or, failing that, empty (e.g. "145_21" or "145") -#: includes/wcs-deprecated-functions.php:180 -msgid "Could not get subscription. Most likely the subscription key does not refer to a subscription. The key was: \"%s\"." -msgstr "" - -#: includes/wcs-formatting-functions.php:41 -msgctxt "initial payment on a subscription" -msgid "up front" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount string (e.g. "£10 / month" ) -#: includes/wcs-formatting-functions.php:99 -msgid "%1$s %2$s then %3$s" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount string, 4$: payment day of the week (e.g. "$15 up front, then $10 every Wednesday") -#: includes/wcs-formatting-functions.php:113 -msgid "%1$s %2$s then %3$s every %4$s" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front" ), 3$: recurring amount, 4$: interval (e.g. "2nd week"), 5$: day of the week (e.g. "Thursday"); (e.g. "$10 up front, then $20 every 2nd week on Wednesday") -#: includes/wcs-formatting-functions.php:122 -msgid "%1$s %2$s then %3$s every %4$s on %5$s" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount; (e.g. "$10 up front then $30 on the last day of each month") -#: includes/wcs-formatting-functions.php:135 -msgid "%1$s %2$s then %3$s on the last day of each month" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up front then $40 on the 23rd of each month") -#: includes/wcs-formatting-functions.php:138 -msgid "%1$s %2$s then %3$s on the %4$s of each month" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: interval (e.g. "3rd") -#: includes/wcs-formatting-functions.php:154 -msgid "%1$s %2$s then %3$s on the last day of every %4$s month" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g. "3rd") -#: includes/wcs-formatting-functions.php:157 -msgid "%1$s %2$s then %3$s on the %4$s day of every %5$s month" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month (e.g. "23rd") -#: includes/wcs-formatting-functions.php:175 -msgid "%1$s %2$s then %3$s on %4$s %5$s each year" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g. "23rd"), 6$: interval (e.g. "3rd") -#: includes/wcs-formatting-functions.php:184 -msgid "%1$s %2$s then %3$s on %4$s %5$s every %6$s year" -msgstr "" - -#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: subscription period (e.g. "month" or "3 months") -#: includes/wcs-formatting-functions.php:194 -msgid "%1$s %2$s then %3$s / %4$s" -msgid_plural "%1$s %2$s then %3$s every %4$s" -msgstr[0] "" -msgstr[1] "" - -#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: trial length (e.g. "3 weeks") -#: includes/wcs-formatting-functions.php:216 -msgid "%1$s after %2$s free trial" -msgstr "" - -#. translators: 1$: trial length (e.g. "3 weeks"), 2$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year") -#: includes/wcs-formatting-functions.php:219 -msgid "%1$s free trial then %2$s" -msgstr "" - -#. translators: placeholder is human time diff (e.g. "3 weeks") -#: includes/wcs-formatting-functions.php:243 -msgid "in %s" -msgstr "" - -#. translators: placeholder is a localized date and time (e.g. "February 1, 2018 10:20 PM") -#: includes/wcs-formatting-functions.php:251 -msgctxt "wcs_get_human_time_diff" -msgid "%s" -msgstr "" - -#. translators: date placeholder for input, javascript format -#: includes/wcs-helper-functions.php:40 -msgid "YYYY-MM-DD" -msgstr "" - -#. translators: hour placeholder for time input, javascript format -#: includes/wcs-helper-functions.php:45 -msgid "HH" -msgstr "" - -#. translators: minute placeholder for time input, javascript format -#: includes/wcs-helper-functions.php:48 -msgid "MM" -msgstr "" - -#. translators: 1) passed sort order type argument, 2) 'ascending', 3) 'descending'. -#: includes/wcs-helper-functions.php:266 -msgid "Invalid sort order type: %1$s. The $sort_order argument must be %2$s or %3$s." -msgstr "" - -#: includes/wcs-order-functions.php:148 -msgctxt "In wcs_copy_order_meta error message. Refers to origin and target order objects." -msgid "Invalid data. Orders expected aren't orders." -msgstr "" - -#: includes/wcs-order-functions.php:152 -msgctxt "Refers to the type of the copy being performed: \"copy_order\", \"subscription\", \"renewal_order\", \"resubscribe_order\"" -msgid "Invalid data. Type of copy is not a string." -msgstr "" - -#. translators: placeholders are strftime() strings. -#. translators: Order date parsed by strftime -#: includes/wcs-order-functions.php:344 -#: wcs-functions.php:161 -msgctxt "Used in subscription post title. \"Subscription renewal order - \"" -msgid "%b %d, %Y @ %I:%M %p" -msgstr "" - -#. translators: placeholder is a date. -#: includes/wcs-order-functions.php:349 -msgid "Subscription Renewal Order – %s" -msgstr "" - -#. translators: placeholder is a date. -#: includes/wcs-order-functions.php:353 -msgid "Resubscribe Order – %s" -msgstr "" - -#: includes/wcs-order-functions.php:372 -msgid "$type passed to the function was not a string." -msgstr "" - -#. translators: placeholder is an order type. -#: includes/wcs-order-functions.php:377 -msgid "\"%s\" is not a valid new order type." -msgstr "" - -#: includes/wcs-order-functions.php:567 -msgid "Invalid data. No valid subscription / order was passed in." -msgstr "" - -#: includes/wcs-order-functions.php:571 -msgid "Invalid data. No valid item id was passed in." -msgstr "" - -#. translators: placeholder is number of days. (e.g. "Bill this every day / 4 days") -#: includes/wcs-time-functions.php:31 -msgctxt "Subscription billing period." -msgid "day" -msgid_plural "%s days" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 weeks") -#: includes/wcs-time-functions.php:33 -msgctxt "Subscription billing period." -msgid "week" -msgid_plural "%s weeks" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is number of months. (e.g. "Bill this every month / 4 months") -#: includes/wcs-time-functions.php:35 -msgctxt "Subscription billing period." -msgid "month" -msgid_plural "%s months" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is number of years. (e.g. "Bill this every year / 4 years") -#: includes/wcs-time-functions.php:37 -msgctxt "Subscription billing period." -msgid "year" -msgid_plural "%s years" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is a number of days. -#: includes/wcs-time-functions.php:58 -msgid "%s day" -msgid_plural "a %s-day" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is a number of weeks. -#: includes/wcs-time-functions.php:60 -msgid "%s week" -msgid_plural "a %s-week" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is a number of months. -#: includes/wcs-time-functions.php:62 -msgid "%s month" -msgid_plural "a %s-month" -msgstr[0] "" -msgstr[1] "" - -#. translators: placeholder is a number of years. -#: includes/wcs-time-functions.php:64 -msgid "%s year" -msgid_plural "a %s-year" -msgstr[0] "" -msgstr[1] "" - -#: includes/wcs-time-functions.php:88 -msgctxt "Subscription length" -msgid "Never expire" -msgstr "" - -#: includes/wcs-time-functions.php:93 -msgctxt "Subscription lengths. e.g. \"For 1 day...\"" -msgid "1 day" -msgstr "" - -#: includes/wcs-time-functions.php:97 -msgctxt "Subscription lengths. e.g. \"For 1 week...\"" -msgid "1 week" -msgstr "" - -#: includes/wcs-time-functions.php:101 -msgctxt "Subscription lengths. e.g. \"For 1 month...\"" -msgid "1 month" -msgstr "" - -#: includes/wcs-time-functions.php:105 -msgctxt "Subscription lengths. e.g. \"For 1 year...\"" -msgid "1 year" -msgstr "" - -#: includes/wcs-time-functions.php:155 -msgctxt "period interval (eg \"$10 _every_ 2 weeks\")" -msgid "every" -msgstr "" - -#. translators: period interval, placeholder is ordinal (eg "$10 every _2nd/3rd/4th_", etc) -#: includes/wcs-time-functions.php:159 -msgctxt "period interval with ordinal number (e.g. \"every 2nd\"" -msgid "every %s" -msgstr "" - -#: includes/wcs-time-functions.php:184 -msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." -msgid "day" -msgid_plural "days" -msgstr[0] "" -msgstr[1] "" - -#: includes/wcs-time-functions.php:185 -msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." -msgid "week" -msgid_plural "weeks" -msgstr[0] "" -msgstr[1] "" - -#: includes/wcs-time-functions.php:186 -msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." -msgid "month" -msgid_plural "months" -msgstr[0] "" -msgstr[1] "" - -#: includes/wcs-time-functions.php:187 -msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." -msgid "year" -msgid_plural "years" -msgstr[0] "" -msgstr[1] "" - -#: includes/wcs-time-functions.php:206 -msgctxt "no trial period" -msgid "no" -msgstr "" - -#: includes/wcs-user-functions.php:345 -#: templates/single-product/add-to-cart/subscription.php:30 -#: templates/single-product/add-to-cart/variable-subscription.php:28 -msgid "Resubscribe" -msgstr "" - -#. translators: placeholder is a currency symbol / code -#: templates/admin/deprecated/html-variation-price.php:20 -#: templates/admin/deprecated/html-variation-price.php:30 -msgid "Subscription Price (%s)" -msgstr "" - -#: templates/admin/deprecated/html-variation-price.php:46 -msgid "Subscription Periods" -msgstr "" - -#: templates/admin/deprecated/html-variation-price.php:59 -msgctxt "Edit product screen, between the Billing Period and Subscription Length dropdowns" -msgid "for" -msgstr "" - -#: templates/admin/deprecated/html-variation-price.php:69 -msgid "Subscription Length" -msgstr "" - -#: templates/admin/deprecated/html-variation-price.php:85 -msgid "Sign-up Fee (%s)" -msgstr "" - -#: templates/admin/deprecated/html-variation-price.php:97 -#: templates/admin/deprecated/html-variation-price.php:104 -msgid "Free Trial" -msgstr "" - -#: templates/admin/deprecated/html-variation-price.php:105 -msgctxt "example number of days / weeks / months" -msgid "e.g. 3" -msgstr "" - -#. translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks") -#: templates/admin/deprecated/html-variation-price.php:118 -#: templates/admin/html-variation-price.php:27 -msgctxt "Trial period dropdown's description in pricing fields" -msgid "An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s" -msgstr "" - -#: templates/admin/deprecated/html-variation-synchronisation.php:30 -msgid "Synchronise Renewals" -msgstr "" - -#: templates/admin/deprecated/order-shipping-html.php:8 -msgid "Label" -msgstr "" - -#: templates/admin/deprecated/order-shipping-html.php:13 -msgid "Shipping Method" -msgstr "" - -#: templates/admin/deprecated/order-shipping-html.php:34 -#: templates/admin/deprecated/order-shipping-html.php:36 -msgid "Other" -msgstr "" - -#: templates/admin/deprecated/order-tax-html.php:17 -msgid "Recurring Sales Tax:" -msgstr "" - -#: templates/admin/deprecated/order-tax-html.php:21 -msgid "Shipping Tax:" -msgstr "" - -#: templates/admin/html-failed-scheduled-action-notice.php:21 -msgid "An error has occurred while processing a recent subscription related event. For steps on how to fix the affected subscription and to learn more about the possible causes of this error, please read our guide %1$shere%2$s." -msgid_plural "An error has occurred while processing recent subscription related events. For steps on how to fix the affected subscriptions and to learn more about the possible causes of this error, please read our guide %1$shere%2$s." -msgstr[0] "" -msgstr[1] "" - -#: templates/admin/html-failed-scheduled-action-notice.php:31 -msgid "Affected event:" -msgid_plural "Affected events:" -msgstr[0] "" -msgstr[1] "" - -#. translators: $1 the log file name $2 and $3 are opening and closing link tags, respectively. -#: templates/admin/html-failed-scheduled-action-notice.php:38 -msgid "To see further details about these errors, view the %1$s log file from the %2$sWooCommerce logs screen.%2$s" -msgstr "" - -#: templates/admin/html-variation-price.php:31 -msgid "Subscription trial period:" -msgstr "" - -#: templates/admin/html-variation-price.php:49 -msgid "Billing interval:" -msgstr "" - -#: templates/admin/html-variation-price.php:56 -msgid "Billing Period:" -msgstr "" - -#: templates/admin/html-variation-price.php:67 -msgctxt "Subscription Length dropdown's description in pricing fields" -msgid "Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date." -msgstr "" - -#: templates/cart/cart-recurring-shipping.php:32 -msgid "Shipping costs will be calculated once you have provided your address." -msgstr "" - -#: templates/cart/cart-recurring-shipping.php:34 -msgid "There are no shipping methods available. Please double check your address, or contact us if you need any help." -msgstr "" - -#: templates/checkout/form-change-payment-method.php:20 -#: templates/emails/email-order-details.php:36 -#: templates/myaccount/subscription-totals-table.php:21 -msgctxt "table headings in notification email" -msgid "Product" -msgstr "" - -#: templates/checkout/form-change-payment-method.php:21 -#: templates/emails/email-order-details.php:37 -msgctxt "table headings in notification email" -msgid "Quantity" -msgstr "" - -#: templates/checkout/form-change-payment-method.php:22 -msgctxt "table headings in notification email" -msgid "Totals" -msgstr "" - -#: templates/checkout/form-change-payment-method.php:47 -msgctxt "text on button on checkout page" -msgid "Change payment method" -msgstr "" - -#: templates/checkout/form-change-payment-method.php:49 -msgctxt "text on button on checkout page" -msgid "Add payment method" -msgstr "" - -#: templates/checkout/form-change-payment-method.php:82 -msgid "Sorry, it seems no payment gateways support changing the recurring payment method. Please contact us if you require assistance or to make alternate arrangements." -msgstr "" - -#. translators: $1: opening tag, $2: closing tag -#: templates/checkout/form-change-payment-method.php:91 -msgid "Update the payment method used for %1$sall%2$s of my current subscriptions" -msgstr "" - -#: templates/checkout/recurring-totals.php:19 -msgid "Recurring totals" -msgstr "" - -#: templates/checkout/recurring-totals.php:31 -#: templates/checkout/recurring-totals.php:32 -msgid "Subtotal" -msgstr "" - -#: templates/checkout/recurring-totals.php:151 -#: templates/checkout/recurring-totals.php:152 -msgid "Recurring total" -msgstr "" - -#. translators: placeholder is the subscription order number wrapped in tags -#: templates/checkout/subscription-receipt.php:18 -#: templates/emails/plain/email-order-details.php:19 -msgid "Subscription Number: %s" -msgstr "" - -#. translators: placeholder is the subscription's next payment date (either human readable or normal date) wrapped in tags -#: templates/checkout/subscription-receipt.php:24 -msgid "Next Payment Date: %s" -msgstr "" - -#. translators: placeholder is the formatted total to be paid for the subscription wrapped in tags -#: templates/checkout/subscription-receipt.php:30 -msgid "Total: %s" -msgstr "" - -#. translators: placeholder is the display name of the payment method -#: templates/checkout/subscription-receipt.php:37 -msgid "Payment Method: %s" -msgstr "" - -#. translators: $1: customer's billing first name and last name -#: templates/emails/admin-new-renewal-order.php:16 -#: templates/emails/plain/admin-new-renewal-order.php:16 -msgctxt "Used in admin email: new renewal order" -msgid "You have received a subscription renewal order from %1$s. Their order is as follows:" -msgstr "" - -#. translators: $1: customer's first name and last name, $2: how many subscriptions customer switched -#: templates/emails/admin-new-switch-order.php:18 -#: templates/emails/plain/admin-new-switch-order.php:18 -msgctxt "Used in switch notification admin email" -msgid "Customer %1$s has switched their subscription. The details of their new subscription are as follows:" -msgid_plural "Customer %1$s has switched %2$d of their subscriptions. The details of their new subscriptions are as follows:" -msgstr[0] "" -msgstr[1] "" - -#: templates/emails/admin-new-switch-order.php:20 -msgid "Switch Order Details" -msgstr "" - -#: templates/emails/admin-new-switch-order.php:28 -#: templates/emails/customer-completed-switch-order.php:26 -msgid "New subscription details" -msgstr "" - -#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' -#: templates/emails/admin-payment-retry.php:23 -msgctxt "In customer renewal invoice email" -msgid "The automatic recurring payment for order #%d from %s has failed. The payment will be retried %3$s." -msgstr "" - -#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' -#: templates/emails/admin-payment-retry.php:24 -#: templates/emails/plain/admin-payment-retry.php:21 -msgid "The renewal order is as follows:" -msgstr "" - -#. translators: $1: customer's billing first name and last name -#: templates/emails/cancelled-subscription.php:16 -#: templates/emails/plain/cancelled-subscription.php:16 -msgid "A subscription belonging to %1$s has been cancelled. Their subscription's details are as follows:" -msgstr "" - -#: templates/emails/cancelled-subscription.php:22 -#: templates/emails/email-order-details.php:38 -#: templates/emails/expired-subscription.php:22 -#: templates/emails/on-hold-subscription.php:22 -msgctxt "table headings in notification email" -msgid "Price" -msgstr "" - -#: templates/emails/cancelled-subscription.php:23 -#: templates/emails/expired-subscription.php:23 -#: templates/emails/on-hold-subscription.php:23 -#: tests/unit/scheduler/scheduler.php:68 -#: wcs-functions.php:306 -msgctxt "table heading" -msgid "Last Order Date" -msgstr "" - -#: templates/emails/cancelled-subscription.php:24 -msgctxt "table headings in notification email" -msgid "End of Prepaid Term" -msgstr "" - -#: templates/emails/cancelled-subscription.php:41 -#: templates/emails/expired-subscription.php:41 -#: templates/emails/on-hold-subscription.php:41 -msgid "-" -msgstr "" - -#. translators: %s: Customer first name -#: templates/emails/customer-completed-renewal-order.php:17 -#: templates/emails/customer-completed-switch-order.php:17 -#: templates/emails/customer-on-hold-renewal-order.php:17 -#: templates/emails/customer-payment-retry.php:16 -#: templates/emails/customer-processing-renewal-order.php:17 -#: templates/emails/customer-renewal-invoice.php:16 -#: templates/emails/plain/customer-completed-renewal-order.php:16 -#: templates/emails/plain/customer-completed-switch-order.php:16 -#: templates/emails/plain/customer-on-hold-renewal-order.php:16 -#: templates/emails/plain/customer-payment-retry.php:16 -#: templates/emails/plain/customer-processing-renewal-order.php:16 -#: templates/emails/plain/customer-renewal-invoice.php:16 -msgid "Hi %s," -msgstr "" - -#: templates/emails/customer-completed-renewal-order.php:18 -#: templates/emails/plain/customer-completed-renewal-order.php:17 -msgid "We have finished processing your subscription renewal order." -msgstr "" - -#: templates/emails/customer-completed-switch-order.php:18 -#: templates/emails/plain/customer-completed-switch-order.php:17 -msgid "You have successfully changed your subscription items. Your new order and subscription details are shown below for your reference:" -msgstr "" - -#: templates/emails/customer-on-hold-renewal-order.php:18 -#: templates/emails/plain/customer-on-hold-renewal-order.php:17 -msgid "Thanks for your renewal order. It’s on-hold until we confirm that payment has been received. In the meantime, here’s a reminder of your order:" -msgstr "" - -#. translators: %s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' -#: templates/emails/customer-payment-retry.php:18 -#: templates/emails/plain/customer-payment-retry.php:18 -msgctxt "In customer renewal invoice email" -msgid "The automatic payment to renew your subscription has failed. We will retry the payment %s." -msgstr "" - -#. translators: %1$s %2$s: link markup to checkout payment url, note: no full stop due to url at the end -#: templates/emails/customer-payment-retry.php:21 -msgctxt "In customer renewal invoice email" -msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$sPay Now »%2$s" -msgstr "" - -#. translators: %s: Order number -#: templates/emails/customer-processing-renewal-order.php:19 -#: templates/emails/plain/customer-processing-renewal-order.php:18 -msgid "Just to let you know — we've received your subscription renewal order #%s, and it is now being processed:" -msgstr "" - -#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end -#: templates/emails/customer-renewal-invoice.php:22 -#: templates/emails/plain/customer-renewal-invoice.php:20 -msgctxt "In customer renewal invoice email" -msgid "An order has been created for you to renew your subscription on %1$s. To pay for this invoice please use the following link: %2$s" -msgstr "" - -#: templates/emails/customer-renewal-invoice.php:24 -#: templates/emails/customer-renewal-invoice.php:33 -msgid "Pay Now »" -msgstr "" - -#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end -#: templates/emails/customer-renewal-invoice.php:31 -#: templates/emails/plain/customer-renewal-invoice.php:23 -msgctxt "In customer renewal invoice email" -msgid "The automatic payment to renew your subscription with %1$s has failed. To reactivate the subscription, please log in and pay for the renewal from your account page: %2$s" -msgstr "" - -#. translators: $1-$2: opening and closing tags $3: order's order number $4: date of order in tags $2: subscription's order number -#: templates/emails/email-order-details.php:27 -msgctxt "Used in email notification" -msgid "Subscription %1$s#%2$s%3$s" -msgstr "" - -#: templates/emails/email-order-details.php:61 -msgid "Note:" -msgstr "" - -#. translators: $1: customer's billing first name and last name -#: templates/emails/expired-subscription.php:16 -#: templates/emails/plain/expired-subscription.php:16 -msgid "A subscription belonging to %1$s has expired. Their subscription's details are as follows:" -msgstr "" - -#: templates/emails/expired-subscription.php:24 -msgctxt "table headings in notification email" -msgid "End Date" -msgstr "" - -#. translators: $1: customer's billing first name and last name -#: templates/emails/on-hold-subscription.php:16 -#: templates/emails/plain/on-hold-subscription.php:16 -msgid "A subscription belonging to %1$s has been suspended by the user. Their subscription's details are as follows:" -msgstr "" - -#: templates/emails/on-hold-subscription.php:24 -msgctxt "table headings in notification email" -msgid "Date Suspended" -msgstr "" - -#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' -#: templates/emails/plain/admin-payment-retry.php:20 -msgctxt "In customer renewal invoice email" -msgid "The automatic recurring payment for order #%1$s from %2$s has failed. The payment will be retried %3$s." -msgstr "" - -#. translators: placeholder is last time subscription was paid -#: templates/emails/plain/cancelled-subscription.php:32 -#: templates/emails/plain/expired-subscription.php:32 -msgid "Last Order Date: %s" -msgstr "" - -#. translators: placeholder is localised date string -#: templates/emails/plain/cancelled-subscription.php:39 -msgid "End of Prepaid Term: %s" -msgstr "" - -#: templates/emails/plain/cancelled-subscription.php:44 -#: templates/emails/plain/expired-subscription.php:44 -#: templates/emails/plain/on-hold-subscription.php:40 -msgctxt "in plain emails for subscription information" -msgid "View Subscription: %s" -msgstr "" - -#. translators: placeholder is order's view url -#: templates/emails/plain/customer-completed-switch-order.php:24 -msgid "View your order: %s" -msgstr "" - -#. translators: placeholder is subscription's view url -#: templates/emails/plain/customer-completed-switch-order.php:35 -msgid "View your subscription: %s" -msgstr "" - -#. translators: %1$s: link to checkout payment url, note: no full stop due to url at the end -#: templates/emails/plain/customer-payment-retry.php:21 -msgctxt "In customer renewal invoice email" -msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$s" -msgstr "" - -#: templates/emails/plain/email-order-details.php:16 -msgid "Order number: %s" -msgstr "" - -#: templates/emails/plain/email-order-details.php:17 -msgid "Order date: %s" -msgstr "" - -#. translators: placeholder is localised date string -#: templates/emails/plain/expired-subscription.php:39 -msgid "End Date: %s" -msgstr "" - -#. translators: placeholder is last time subscription was paid -#: templates/emails/plain/on-hold-subscription.php:32 -msgid "Last Order: %s" -msgstr "" - -#. translators: placeholder is localised date string -#: templates/emails/plain/on-hold-subscription.php:36 -msgid "Date Suspended: %s" -msgstr "" - -#: templates/emails/plain/subscription-info.php:20 -#: templates/emails/subscription-info.php:21 -msgid "Subscription information" -msgstr "" - -#. translators: placeholder is subscription's number -#: templates/emails/plain/subscription-info.php:25 -msgctxt "in plain emails for subscription information" -msgid "Subscription: %s" -msgstr "" - -#. translators: placeholder is either view or edit url for the subscription -#: templates/emails/plain/subscription-info.php:27 -msgctxt "in plain emails for subscription information" -msgid "View subscription: %s" -msgstr "" - -#. translators: placeholder is localised start date -#: templates/emails/plain/subscription-info.php:29 -msgctxt "in plain emails for subscription information" -msgid "Start date: %s" -msgstr "" - -#: templates/emails/plain/subscription-info.php:31 -msgctxt "Used as end date for an indefinite subscription" -msgid "When Cancelled" -msgstr "" - -#. translators: placeholder is localised end date, or "when cancelled" -#: templates/emails/plain/subscription-info.php:33 -msgctxt "in plain emails for subscription information" -msgid "End date: %s" -msgstr "" - -#. translators: placeholder is the formatted order total for the subscription -#: templates/emails/plain/subscription-info.php:35 -msgctxt "in plain emails for subscription information" -msgid "Recurring price: %s" -msgstr "" - -#: templates/emails/plain/subscription-info.php:38 -#: templates/emails/subscription-info.php:42 -msgid "Next payment: %s" -msgstr "" - -#. Translators: Placeholder is the My Account URL. -#: templates/emails/plain/subscription-info.php:51 -msgid "This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your my account page. %s" -msgid_plural "These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your my account page. %s" -msgstr[0] "" -msgstr[1] "" - -#: templates/emails/subscription-info.php:25 -msgctxt "subscription ID table heading" -msgid "ID" -msgstr "" - -#: templates/emails/subscription-info.php:26 -msgctxt "table heading" -msgid "Start date" -msgstr "" - -#: templates/emails/subscription-info.php:27 -msgctxt "table heading" -msgid "End date" -msgstr "" - -#: templates/emails/subscription-info.php:28 -msgctxt "table heading" -msgid "Recurring total" -msgstr "" - -#: templates/emails/subscription-info.php:35 -msgctxt "subscription number in email table. (eg: #106)" -msgid "#%s" -msgstr "" - -#: templates/emails/subscription-info.php:37 -msgctxt "Used as end date for an indefinite subscription" -msgid "When cancelled" -msgstr "" - -#. Translators: Placeholders are opening and closing My Account link tags. -#: templates/emails/subscription-info.php:57 -msgid "This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your %smy account page%s." -msgid_plural "These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your %smy account page%s." -msgstr[0] "" -msgstr[1] "" - #: templates/html-early-renewal-modal-content.php:23 msgid "By renewing your subscription early your next payment will be %s." msgstr "" @@ -5881,312 +1849,1476 @@ msgstr "" msgid "Want to renew early via the checkout? Click %shere.%s" msgstr "" -#: templates/myaccount/my-subscriptions.php:23 -#: templates/myaccount/related-subscriptions.php:23 -#: templates/myaccount/related-subscriptions.php:39 -msgctxt "table heading" -msgid "Next payment" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:33 -#: templates/myaccount/related-subscriptions.php:31 -msgid "ID" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:40 -#: tests/unit/scheduler/scheduler.php:67 -#: wcs-functions.php:305 -msgctxt "table heading" -msgid "Next Payment" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:46 -#: templates/myaccount/related-orders.php:53 -#: templates/myaccount/related-subscriptions.php:42 -msgctxt "Used in data attribute. Escaped" -msgid "Total" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:50 -#: templates/myaccount/related-orders.php:84 -#: templates/myaccount/related-subscriptions.php:46 -msgctxt "view a subscription" -msgid "View" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:61 -msgid "Previous" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:65 -msgid "Next" -msgstr "" - -#: templates/myaccount/my-subscriptions.php:72 -msgid "You have reached the end of subscriptions. Go to the %sfirst page%s." -msgstr "" - -#: templates/myaccount/my-subscriptions.php:74 -msgid "You have no active subscriptions." -msgstr "" - -#: templates/myaccount/my-subscriptions.php:77 -msgid "Browse products" -msgstr "" - -#: templates/myaccount/related-orders.php:15 -msgid "Related orders" -msgstr "" - -#: templates/myaccount/related-orders.php:22 -msgid "Order" -msgstr "" - -#. translators: $1: formatted order total for the order, $2: number of items bought -#: templates/myaccount/related-orders.php:56 -msgid "%1$s for %2$d item" -msgid_plural "%1$s for %2$d items" -msgstr[0] "" -msgstr[1] "" - -#: templates/myaccount/related-orders.php:65 -msgctxt "pay for a subscription" -msgid "Pay" -msgstr "" - -#: templates/myaccount/related-subscriptions.php:15 -msgid "Related subscriptions" -msgstr "" - -#: templates/myaccount/subscription-details.php:24 -msgctxt "customer subscription table header" -msgid "Start date" -msgstr "" - -#: templates/myaccount/subscription-details.php:25 -msgctxt "customer subscription table header" -msgid "Last order date" -msgstr "" - -#: templates/myaccount/subscription-details.php:26 -msgctxt "customer subscription table header" -msgid "Next payment date" -msgstr "" - -#: templates/myaccount/subscription-details.php:27 -msgctxt "customer subscription table header" -msgid "End date" -msgstr "" - -#: templates/myaccount/subscription-details.php:28 -msgctxt "customer subscription table header" -msgid "Trial end date" -msgstr "" - -#: templates/myaccount/subscription-details.php:42 -msgid "Auto renew" -msgstr "" - -#: templates/myaccount/subscription-details.php:50 -msgid "Enable auto renew" -msgstr "" - -#: templates/myaccount/subscription-details.php:57 -msgid "Disable auto renew" -msgstr "" - -#: templates/myaccount/subscription-details.php:62 -msgid "Using the auto-renewal toggle is disabled while in staging mode." -msgstr "" - -#: templates/myaccount/subscription-details.php:71 -msgid "Payment" -msgstr "" - -#: templates/myaccount/subscription-details.php:81 -msgid "Actions" -msgstr "" - -#: templates/myaccount/subscription-details.php:94 -msgid "Subscription updates" -msgstr "" - -#: templates/myaccount/subscription-details.php:100 -msgctxt "date on subscription updates list. Will be localized" -msgid "l jS \\o\\f F Y, h:ia" -msgstr "" - -#: templates/myaccount/subscription-totals-table.php:35 -msgid "Are you sure you want remove this item from your subscription?" -msgstr "" - -#: templates/myaccount/subscription-totals.php:23 -msgid "Subscription totals" -msgstr "" - -#: templates/single-product/add-to-cart/subscription.php:32 -#: templates/single-product/add-to-cart/variable-subscription.php:30 -msgid "You have an active subscription to this product already." -msgstr "" - -#: templates/single-product/add-to-cart/variable-subscription.php:23 -msgid "This product is currently out of stock and unavailable." -msgstr "" - -#: templates/single-product/add-to-cart/variable-subscription.php:34 -msgid "You have added a variation of this product to the cart already." -msgstr "" - -#: templates/single-product/add-to-cart/variable-subscription.php:45 -msgid "Clear" -msgstr "" - #: tests/unit/scheduler/scheduler.php:65 -#: wcs-functions.php:303 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:300 msgctxt "table heading" msgid "Start Date" msgstr "" #: tests/unit/scheduler/scheduler.php:66 -#: wcs-functions.php:304 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:301 msgctxt "table heading" msgid "Trial End" msgstr "" +#: tests/unit/scheduler/scheduler.php:67 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:40 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:302 +msgctxt "table heading" +msgid "Next Payment" +msgstr "" + +#: tests/unit/scheduler/scheduler.php:68 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:303 +msgctxt "table heading" +msgid "Last Order Date" +msgstr "" + #: tests/unit/scheduler/scheduler.php:69 -#: wcs-functions.php:307 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:304 msgctxt "table heading" msgid "Cancelled Date" msgstr "" #: tests/unit/scheduler/scheduler.php:70 -#: wcs-functions.php:308 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:305 msgctxt "table heading" msgid "End Date" msgstr "" -#: tests/unit/wcs_test_wcs_functions.php:833 -msgctxt "table column header" -msgid "Big Bang" +#. translators: 1: relation type, 2: list of valid relation types. +#: vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php:148 +msgid "Invalid relation type: %1$s. Order relationship type must be one of: %2$s." msgstr "" -#: wcs-functions.php:130 -msgctxt "Error message while creating a subscription" -msgid "Invalid created date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:208 +msgid "Simple subscription" msgstr "" -#: wcs-functions.php:132 -msgctxt "Error message while creating a subscription" -msgid "Subscription created date must be before current day." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:209 +msgid "Variable subscription" msgstr "" -#: wcs-functions.php:137 -msgctxt "Error message while creating a subscription" -msgid "Invalid date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:230 +msgid "Downloadable" msgstr "" -#: wcs-functions.php:142 -msgctxt "Error message while creating a subscription" -msgid "Invalid subscription customer_id." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:231 +msgid "Virtual" msgstr "" -#. translators: placeholder is order date parsed by strftime -#: wcs-functions.php:163 -msgctxt "The post title for the new subscription" -msgid "Subscription – %s" +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:295 +msgid "Choose the subscription price, billing interval and period." msgstr "" -#: wcs-functions.php:234 -msgctxt "Subscription status" -msgid "On hold" +#. translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks") +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:297 +msgctxt "Trial period field tooltip on Edit Product administration screen" +msgid "An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s" msgstr "" -#: wcs-functions.php:238 -msgctxt "Subscription status" -msgid "Pending Cancellation" +#. translators: %s: currency symbol. +#. translators: placeholder is a currency symbol / code +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:311 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:44 +msgid "Subscription price (%s)" msgstr "" -#: wcs-functions.php:254 -msgid "Can not get status name. Status is not a string." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:315 +msgctxt "example price" +msgid "e.g. 5.90" msgstr "" -#: wcs-functions.php:277 -msgid "Can not get address type display name. Address type is not a string." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:316 +msgid "Subscription interval" msgstr "" -#: wcs-functions.php:343 -msgid "Date type is not a string." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:322 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:470 +msgid "Subscription period" msgstr "" -#: wcs-functions.php:345 -msgid "Date type can not be an empty string." +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:337 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:471 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:66 +msgid "Expire after" msgstr "" -#: woocommerce-subscriptions.php:265 -msgctxt "custom post type setting" -msgid "Add Subscription" +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:340 +msgid "Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date." msgstr "" -#: woocommerce-subscriptions.php:266 -msgctxt "custom post type setting" -msgid "Add New Subscription" +#. translators: %s is a currency symbol / code +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:350 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:20 +msgid "Sign-up fee (%s)" msgstr "" -#: woocommerce-subscriptions.php:267 -msgctxt "custom post type setting" -msgid "Edit" +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:351 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:31 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:86 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:21 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:47 +msgctxt "example price" +msgid "e.g. 9.90" msgstr "" -#: woocommerce-subscriptions.php:268 -msgctxt "custom post type setting" +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:352 +msgid "Optionally include an amount to be charged at the outset of the subscription. The sign-up fee will be charged immediately, even if the product has a free trial or the payment dates are synced." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:364 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2483 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:25 +msgid "Free trial" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:367 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:115 +msgid "Subscription Trial Period" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:405 +msgid "One time shipping" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:406 +msgid "Shipping for subscription products is normally charged on the initial order and all renewal orders. Enable this to only charge shipping once on the initial order. Note: for this setting to be enabled the subscription must not have a free trial or a synced renewal date." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:467 +msgid "Subscription pricing" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:468 +msgid "Subscription sign-up fee" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:469 +msgid "Subscription billing interval" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:472 +msgid "Free trial length" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:473 +msgid "Free trial period" +msgstr "" + +#. translators: %s: subscription status. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:798 +msgid "Unable to change subscription status to \"%s\". Please assign a customer to the subscription to activate it." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:839 +msgid "Trashing this order will also trash the subscriptions purchased with the order." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:852 +msgid "Enter the new period, either day, week, month or year:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:853 +msgid "Enter a new length (e.g. 5):" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:854 +msgid "Enter a new interval as a single number (e.g. to charge every 2nd month, enter 2):" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:855 +msgid "Delete all variations without a subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:861 +msgid "An error occurred determining if that variation can be deleted. Please try again." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:862 +msgid "That variation can not be removed because it is associated with active subscriptions. To remove this variation, please cancel and delete the subscriptions for it." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:867 +msgid "" +"You are about to trash one or more orders which contain a subscription.\n" +"\n" +"Trashing the orders will also trash the subscriptions purchased with these orders." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:880 +msgid "" +"WARNING: Bad things are about to happen!\n" +"\n" +"The payment gateway used to purchase this subscription does not support modifying a subscription's details.\n" +"\n" +"Changes to the billing period, recurring discount, recurring tax or recurring total may not be reflected in the amount charged by the payment gateway." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:881 +msgid "You are deleting a subscription item. You will also need to manually cancel and trash the subscription on the Manage Subscriptions screen." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:888 +msgid "" +"Warning: Deleting a user will also delete the user's subscriptions. The user's orders will remain but be reassigned to the 'Guest' user.\n" +"\n" +"Do you want to continue to delete this user and any associated subscriptions?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:892 +msgid "PayPal Standard has a number of limitations and does not support all subscription features." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:892 +msgid "Because of this, it is not recommended as a payment method for Subscriptions unless it is the only available option for your country." +msgstr "" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: "

    ", 3$: "

    ", 4$: "", 5$: "", 6$: "", 7$: "", 8$: "

    " +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:910 +msgctxt "used in admin pointer script params in javascript as type pointer content" +msgid "%1$sChoose Subscription%2$s%3$sThe WooCommerce Subscriptions extension adds two new subscription product types - %4$sSimple subscription%5$s and %6$sVariable subscription%7$s.%8$s" +msgstr "" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: "

    ", 3$: "

    ", 4$: "

    " +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:912 +msgctxt "used in admin pointer script params in javascript as price pointer content" +msgid "%1$sSet a Price%2$s%3$sSubscription prices are a little different to other product prices. For a subscription, you can set a billing period, length, sign-up fee and free trial.%4$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:942 +msgid "Active subscriber?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:985 +msgid "Manage Subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:989 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:347 +msgid "Search Subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1209 +msgctxt "options section heading" +msgid "Miscellaneous" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1216 +msgid "Mixed Checkout" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1217 +msgid "Allow multiple subscriptions and products to be purchased simultaneously." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1221 +msgid "Allow a subscription product to be purchased with other products and subscriptions in the same transaction." +msgstr "" + +#. translators: placeholder is a number +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1322 +msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" +msgstr "" + +#. translators: Placeholders are opening and closing link tags. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1366 +msgid "We weren't able to locate the set of report results you requested. Please regenerate the link from the %1$sSubscription Reports screen%2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1420 +msgid "We can't find a paid subscription order for this user." +msgstr "" + +#. translators: placeholders are opening link tag, ID of sub, and closing link tag +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1452 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1457 +msgid "Showing orders for %1$sSubscription %2$s%3$s" +msgstr "" + +#. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1481 +msgid "The trial period can not exceed: %1$s, %2$s, %3$s or %4$s." +msgstr "" + +#. translators: placeholder is a time period (e.g. "4 weeks") +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1486 +msgid "The trial period can not exceed %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1548 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:93 +msgctxt "label that indicates whether debugging is turned on for the plugin" +msgid "WCS_DEBUG" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1554 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:107 +msgctxt "Live or Staging, Label on WooCommerce -> System Status page" +msgid "Subscriptions Mode" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1555 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to staging site" +msgid "Staging" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1555 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to live site" +msgid "Live" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1585 +msgid "Automatic Recurring Payments" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1618 +msgid "Supports automatic renewal payments." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1716 +msgid "Subscription items can no longer be edited." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1720 +msgid "This subscription is no longer editable because the payment gateway does not allow modification of recurring amounts." +msgstr "" + +#. translators: $1-2: opening and closing tags of a link that takes to Woo marketplace / Stripe product page +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1739 +msgid "No payment gateways capable of processing automatic subscription payments are enabled. If you would like to process automatic payments, we recommend the %1$sfree Stripe extension%2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1746 +msgid "Recurring Payments" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1754 +msgid "Payment gateways which don't support automatic recurring payments can be used to process %1$smanual subscription renewal payments%2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1874 +msgid "Note that purchasing a subscription still requires an account." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1888 +msgid "The product type can not be changed because this product is associated with subscriptions." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1942 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1943 +msgid "Allow subscription customers to create an account during checkout" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:79 +msgctxt "meta box title" +msgid "Subscription Data" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:81 +msgctxt "meta box title" +msgid "Schedule" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:85 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:89 +msgid "Related Orders" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:129 +msgid "Please enter a start date in the past." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:130 +msgid "Please enter a date at least 2 minutes into the future." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:130 +msgid "Please enter a date at least one hour into the future." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:131 +msgid "Please enter a date after the trial end." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:132 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:133 +msgid "Please enter a date after the start date." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:134 +msgid "Please enter a date before the next payment." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:135 +msgid "Please enter a date after the next payment." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:136 +msgid "" +"Are you sure you want to process a renewal?\n" +"\n" +"This will charge the customer and email them the renewal order (if emails are enabled)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:150 +msgid "" +"Are you sure you want to retry payment for this renewal order?\n" +"\n" +"This will attempt to charge the customer and send renewal order emails (if emails are enabled)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:183 +msgid "Process renewal" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:187 +msgid "Create pending renewal order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:189 +msgid "Create pending parent order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:193 +msgid "Retry Renewal Payment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:206 +msgid "Process renewal order action requested by admin." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:217 +msgid "Create pending renewal order requested by admin action." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:259 +msgid "Create pending parent order requested by admin action." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:290 +msgid "Retry renewal payment action requested by admin." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:386 +msgid "This order contains line items with prices above the current product price. To override the product's live price when the customer pays for this order, lock in the manual price increases." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php:390 +msgid "Lock manual price increases" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:214 +msgid "Search for a product…" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:258 +msgctxt "an action on a subscription" +msgid "Activate" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:259 +msgctxt "an action on a subscription" +msgid "Put on-hold" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:260 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:499 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1853 +#: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:327 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:78 +msgctxt "an action on a subscription" +msgid "Cancel" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:338 +msgctxt "Used in order note. Reason why status changed." +msgid "Subscription status changed by bulk edit:" +msgstr "" + +#. translators: placeholder is the number of subscriptions updated +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:394 +msgid "%s subscription status changed." +msgid_plural "%s subscription statuses changed." +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: is the number of subscriptions not updated, 2$: is the error message +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:401 +msgid "%1$s subscription could not be updated: %2$s" +msgid_plural "%1$s subscriptions could not be updated: %2$s" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:425 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php:20 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:22 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:37 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:24 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:50 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:22 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:36 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:18 +msgid "Status" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:426 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:339 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:21 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:21 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:21 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:21 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:21 +msgid "Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:427 +msgid "Items" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:428 +#: vendor/woocommerce/subscriptions-core/build/index.js:11 +#: vendor/woocommerce/subscriptions-core/build/index.js:17 +msgid "Total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:429 +msgid "Start Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:430 +msgid "Trial End" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:431 +msgid "Next Payment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:432 +msgid "Last Order Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:433 +msgid "End Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:434 +msgctxt "number of orders linked to a subscription" +msgid "Orders" +msgstr "" + +#. translators: placeholder is a subscription ID. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:455 +msgctxt "hash before subscription number" +msgid "#%s" +msgstr "" + +#. Translators: Placeholder is a
    HTML tag. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:461 +msgid "This subscription couldn't be loaded from the database. %s Click to learn more." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:497 +#: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:311 +msgid "Reactivate" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:500 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:515 +msgid "Trash" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:501 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:519 +msgid "Delete Permanently" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:513 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:768 +msgid "Restore this item from the Trash" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:513 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:769 +msgid "Restore" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:515 +msgid "Move this item to the Trash" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:519 +msgid "Delete this item permanently" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:525 +msgid "Cancel Now" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:553 +msgctxt "meaning billing address" +msgid "Billing:" +msgstr "" + +#. translators: placeholder is customer's billing email +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:558 +msgid "Email: %s" +msgstr "" + +#. translators: placeholder is customer's billing phone number +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:563 +msgid "Tel: %s" +msgstr "" + +#. translators: $1: is opening link, $2: is subscription order number, $3: is closing link tag, $4: is user's name +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:591 +msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)" +msgid "%1$s#%2$s%3$s for %4$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:595 +msgid "Show more details" +msgstr "" + +#. translators: %d: item count. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:616 +msgid "%d item" +msgid_plural "%d items" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is the display name of a payment gateway a subscription was paid by +#. translators: %s: payment method. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:635 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2026 +msgid "Via %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:677 +msgid "Y/m/d g:i:s A" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:680 +msgid "This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:933 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:936 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:939 +msgid "Subscription updated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:934 +msgid "Custom field updated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:935 +msgid "Custom field deleted." +msgstr "" + +#. translators: placeholder is previous post title +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:938 +msgctxt "used in post updated messages" +msgid "Subscription restored to revision from %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:940 +msgid "Subscription saved." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:941 +msgid "Subscription submitted." +msgstr "" + +#. translators: php date string +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:943 +msgid "Subscription scheduled for: %1$s." +msgstr "" + +#. translators: php date string +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:943 +msgctxt "used in \"Subscription scheduled for \"" +msgid "M j, Y @ G:i" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:944 +msgid "Subscription draft updated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:980 +msgid "Any Payment Method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:981 +msgid "None" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:987 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2008 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:170 +msgid "Manual Renewal" +msgstr "" + +#. translators: 1: user display name 2: user ID 3: user email +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1133 +msgid "%1$s (#%2$s – %3$s)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1140 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:85 +msgid "Search for a customer…" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-product-import-export-manager.php:32 +msgid "Subscription variations" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:57 +msgid "This section shows any information about Subscriptions." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:61 +msgid "Store Setup" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:62 +msgid "This section shows general information about the store." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:66 +msgid "Subscriptions by Payment Gateway" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:67 +msgid "This section shows information about Subscription payment methods." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:71 +msgid "Payment Gateway Support" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:72 +msgid "This section shows information about payment gateway feature support." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:119 +msgctxt "Live URL, Label on WooCommerce -> System Status page" +msgid "Subscriptions Live URL" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:135 +msgctxt "label for the system status page" +msgid "Subscriptions Template Theme Overrides" +msgstr "" + +#. translators: placeholders are opening/closing tags linking to documentation on outdated templates. +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:145 +msgid "%1$sLearn how to update%2$s" +msgstr "" + +#. translators: %1$s is the file version, %2$s is the core version +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:191 +msgid "version %1$s is out of date. The core version is %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:212 +msgctxt "label for the system status page" +msgid "Subscription Statuses" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:233 +msgctxt "label for the system status page" +msgid "WooCommerce Account Connected" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:256 +msgctxt "label for the system status page" +msgid "Active Product Key" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:274 +msgctxt "label for the system status page" +msgid "Other" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:308 +msgctxt "label for the system status page" +msgid "PayPal Reference Transactions Enabled" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:336 +msgctxt "label for the system status page" +msgid "Country / State" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:49 +msgid "Add New" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:59 msgid "Edit Subscription" msgstr "" -#: woocommerce-subscriptions.php:269 -msgctxt "custom post type setting" -msgid "New Subscription" +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:77 +msgctxt "relation to order" +msgid "Subscription" msgstr "" -#: woocommerce-subscriptions.php:270 -#: woocommerce-subscriptions.php:271 -msgctxt "custom post type setting" -msgid "View Subscription" +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:82 +msgctxt "relation to order" +msgid "Initial Subscription" msgstr "" -#: woocommerce-subscriptions.php:274 -msgctxt "custom post type setting" -msgid "No Subscriptions found in trash" +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:93 +msgctxt "relation to order" +msgid "Renewal Order" msgstr "" -#: woocommerce-subscriptions.php:275 -msgctxt "custom post type setting" -msgid "Parent Subscriptions" +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:96 +msgctxt "relation to order" +msgid "Parent Order" msgstr "" -#: woocommerce-subscriptions.php:278 -msgid "This is where subscriptions are stored." +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribed Subscription" msgstr "" -#: woocommerce-subscriptions.php:323 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribe Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:102 +msgctxt "relation to order" +msgid "Unknown Order Type" +msgstr "" + +#. translators: placeholder is the ID of the subscription +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:48 +msgctxt "edit subscription header" +msgid "Subscription #%s details" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:52 +msgid "General" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:55 +msgid "Customer:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:64 +msgid "View other subscriptions →" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:69 +msgid "Profile →" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:93 +msgid "Subscription status:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:110 +msgid "Parent order: " +msgstr "" + +#. translators: placeholder is an order number. +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:114 +msgid "#%1$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:121 +msgid "Parent order:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:127 +msgid "Select an order…" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 +msgid "Billing" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:140 +msgid "Load billing address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:148 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:240 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "Address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +msgid "No billing address set." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:170 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:39 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:52 +msgid "Payment Method" +msgstr "" + +#. translators: %s: gateway ID. +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:175 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:54 +msgctxt "The gateway ID displayed on the Edit Subscriptions screen when editing payment method." +msgid "Gateway ID: [%s]" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:212 +msgid "Customer change payment method page →" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:214 +msgid "Customer add payment method page →" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:228 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:287 +#: vendor/woocommerce/subscriptions-core/build/index.js:6 +msgid "Shipping" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:231 +msgid "Load shipping address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:232 +msgid "Copy billing address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "No shipping address set." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:264 +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:294 +msgid "Customer Provided Note" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:295 +msgid "Customer's notes about the order" +msgstr "" + +#. translators: %s: parent order number (linked to its details screen). +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:387 +msgctxt "subscription note after linking to a parent order" +msgid "Subscription linked to parent order %s via admin." +msgstr "" + +#. translators: placeholder is error message from the payment gateway or subscriptions when updating the status +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:401 +msgid "Error updating some information: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php:17 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:42 +msgid "Order Number" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php:18 +msgid "Relationship" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php:21 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:24 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:25 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:24 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals-table.php:22 +msgctxt "table heading" +msgid "Total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php:34 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:57 +msgid "Billing Period" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php:43 +msgid "Recurring:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Timezone:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Error: unable to find timezone of your browser." +msgstr "" + +#. Translators: The %1 placeholder is the translated order relationship ("Parent Order"), %2 placeholder is a
    HTML tag. +#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:24 +msgid "This %1$s couldn't be loaded from the database. %1$s Click to learn more." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-product-subscription.php:73 +msgid "Read more" +msgstr "" + +#. translators: %s: subscription status. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:423 +msgid "Unable to change subscription status to \"%s\"." +msgstr "" + +#. translators: 1: subscription status, 2: error message. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:546 +msgid "Unable to change subscription status to \"%1$s\". Exception: %2$s" +msgstr "" + +#. translators: 1: old subscription status 2: new subscription status +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:576 +msgid "Status changed from %1$s to %2$s." +msgstr "" + +#. translators: %s: new order status +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:590 +msgid "Status set to %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:604 +msgid "Error during subscription status transition." +msgstr "" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1201 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2303 +msgid "In %s" +msgstr "" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1204 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:246 +msgid "%s ago" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1211 +msgid "Not yet ended" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1214 +msgid "Not cancelled" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1219 +msgctxt "original denotes there is no date to display" +msgid "-" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1327 +msgid "The creation date of a subscription can not be deleted, only updated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1330 +msgid "The start date of a subscription can not be deleted, only updated." +msgstr "" + +#. translators: %s: date type (e.g. "trial_end"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1335 +msgid "The %s date of a subscription can not be deleted. You must delete the order." +msgstr "" + +#. translators: %d: subscription ID. +#. translators: %d: order ID. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1344 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2449 +msgid "Subscription #%d: " +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1758 +msgid "Payment status marked complete." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1786 +msgid "Payment failed." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1791 +msgid "Subscription Cancelled: maximum number of failed payments reached." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1901 +msgid "The \"all\" value for $order_type parameter is deprecated. It was a misnomer, as it did not return resubscribe orders. It was also inconsistent with order type values accepted by wcs_get_subscription_orders(). Use array( \"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or \"any\" to receive all order types, including switch and resubscribe." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2105 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:825 +msgid "Payment method meta must be an array." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2341 +msgid "Invalid format. First parameter needs to be an array." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2345 +msgid "Invalid data. First parameter was empty when passed to update_dates()." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2352 +msgid "Invalid data. First parameter has a date that is not in the registered date types." +msgstr "" + +#. translators: placeholder is date type (e.g. "end", "next_payment"...) +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2379 +msgctxt "appears in an error message if date is wrong format" +msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2417 +msgid "The %s date must occur after the cancellation date." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2423 +msgid "The %s date must occur after the last payment date." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2428 +msgid "The %s date must occur after the next payment date." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2434 +msgid "The %s date must occur after the trial end date." +msgstr "" + +#. translators: %s: date type (e.g. "next_payment"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2439 +msgid "The %s date must occur after the start date." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2469 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:341 +msgid "Backordered" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php:64 +msgid "Change address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php:106 +msgid "Both the shipping address used for the subscription and your default shipping address for future purchases will be updated." +msgstr "" + +#. translators: $1: address type (Shipping Address / Billing Address), $2: opening tag, $3: closing tag +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php:119 +msgid "Update the %1$s used for %2$sall%3$s future renewals of my active subscriptions" +msgstr "" + +#. translators: %s: subscription ID. +#. translators: %s: order number. +#. translators: placeholder is a subscription ID. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php:243 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:739 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:101 +msgctxt "hash before order number" +msgid "Subscription #%s" +msgstr "" + +#. translators: %s: address type (eg. 'billing' or 'shipping'). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php:249 +msgctxt "change billing or shipping address" +msgid "Change %s address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:56 +msgid "A subscription renewal has been removed from your cart. Multiple subscriptions can not be purchased at the same time." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:62 +msgid "A subscription has been removed from your cart. Due to payment gateway restrictions, different subscription products can not be purchased at the same time." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:68 +msgid "A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:107 +msgid "Your cart has been emptied of subscription products. Only one subscription product can be purchased at a time." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:128 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1543 +msgid "That subscription product can not be added to your cart as it already contains a subscription renewal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:493 +msgid "Initial Shipment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:932 +msgid "Please enter a valid postcode/ZIP." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1168 +msgid "Invalid recurring shipping method." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2219 +msgid "now" +msgstr "" + +#. translators: placeholder is a number of days. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2378 +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:58 +msgid "%s day" +msgid_plural "%s days" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a number of weeks. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2382 +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:60 +msgid "%s week" +msgid_plural "%s weeks" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a number of months. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2386 +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:62 +msgid "%s month" +msgid_plural "%s months" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a number of years. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2390 +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:64 +msgid "%s year" +msgid_plural "%s years" +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: day of the week (e.g. "every Wednesday"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2412 +msgid "every %1$s" +msgstr "" + +#. translators: 1$: period, 2$: day of the week (e.g. "every 2nd week on Wednesday"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2416 +msgid "every %1$s on %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2425 +msgid "on the last day of each month" +msgstr "" + +#. translators: 1$: day of the month (e.g. "23rd") (e.g. "every 23rd of each month"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2429 +msgid "on the %1$s of each month" +msgstr "" + +#. translators: 1$: interval (e.g. "3rd") (e.g. "on the last day of every 3rd month"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2437 +msgid "on the last day of every %1$s month" +msgstr "" + +#. translators: on the, 1$: day of every, 2$: month (e.g. "on the 23rd day of every 2nd month"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2443 +msgid "on the %1$s day of every %2$s month" +msgstr "" + +#. translators: on, 1$: , 2$: each year (e.g. "on March 15th each year"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2454 +msgid "on %1$s %2$s each year" +msgstr "" + +#. translators: 1$: month (e.g. "March"), 2$: day of the month (e.g. "23rd), 3$: interval year (r.g March 23rd every 2nd year"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2461 +msgid "on %1$s %2$s every %3$s year" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2493 +msgid "Sign up fee" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2503 +msgid "Renews" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:161 +msgid "Sorry, this subscription change payment method request is invalid and cannot be processed." +msgstr "" + +#. translators: placeholder is next payment's date +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:185 +msgid " Next payment is due %s." +msgstr "" + +#. translators: placeholder is either empty or "Next payment is due..." +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:191 +msgid "Choose a new payment method.%s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:230 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-template-loader.php:105 +#: vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php:286 +msgid "Invalid Subscription." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:236 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:243 +msgid "The payment method can not be changed for that subscription." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:239 +msgid "Invalid order." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:257 +msgctxt "label on button, imperative" +msgid "Change payment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:259 +msgctxt "label on button, imperative" +msgid "Add payment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:320 +msgid "Payment method updated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:320 +msgid "Payment method added." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:360 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:362 +msgid "Payment method updated for all your current subscriptions." +msgstr "" + +#. translators: 1: old payment title, 2: new payment title. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:517 +msgctxt "%1$s: old payment title, %2$s: new payment title" +msgid "Payment method changed from \"%1$s\" to \"%2$s\" by the subscriber." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:528 +msgid "An error occurred updating your subscription's payment method. Please contact us for assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:536 +msgid "%1$sError:%2$s %3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:761 +msgctxt "the page title of the change payment method form" +msgid "Change payment method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:763 +msgctxt "the page title of the add payment method form" +msgid "Add payment method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php:805 +msgid "Please log in to your account below to choose a new payment method for your subscription." +msgstr "" + +#. translators: placeholder is an internal error number +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:203 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:385 +msgid "Error %d: Unable to create subscription. Please try again." +msgstr "" + +#. translators: placeholder is an internal error number +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:220 +msgid "Error %d: Unable to add tax to subscription. Please try again." +msgstr "" + +#. translators: placeholder is an internal error number +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:232 +msgid "Error %d: Unable to create order. Please try again." +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:514 +msgid "Purchasing a subscription product requires an account. Please go to the %1$sMy Account%2$s page to login or register." +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:517 +msgid "Purchasing a subscription product requires an account. Please go to the %1$sMy Account%2$s page to login or contact us if you need assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:320 msgid "No Subscriptions found" msgstr "" -#: woocommerce-subscriptions.php:325 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:322 msgid "Subscriptions will appear here for you to view and manage once purchased by a customer." msgstr "" #. translators: placeholders are opening and closing link tags -#: woocommerce-subscriptions.php:327 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:324 msgid "%1$sLearn more about managing subscriptions »%2$s" msgstr "" #. translators: placeholders are opening and closing link tags -#: woocommerce-subscriptions.php:329 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:326 msgid "%1$sAdd a subscription product »%2$s" msgstr "" +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:340 +msgctxt "custom post type setting" +msgid "Add Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:341 +msgctxt "custom post type setting" +msgid "Add New Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:342 +msgctxt "custom post type setting" +msgid "Edit" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:343 +msgctxt "custom post type setting" +msgid "Edit Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:344 +msgctxt "custom post type setting" +msgid "New Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:345 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:346 +msgctxt "custom post type setting" +msgid "View Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:349 +msgctxt "custom post type setting" +msgid "No Subscriptions found in trash" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:350 +msgctxt "custom post type setting" +msgid "Parent Subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:353 +msgid "This is where subscriptions are stored." +msgstr "" + #. translators: placeholder is a post count. -#: woocommerce-subscriptions.php:344 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:411 msgctxt "post status label including post count" msgid "Active (%s)" msgid_plural "Active (%s)" @@ -6194,7 +3326,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a post count. -#: woocommerce-subscriptions.php:346 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:413 msgctxt "post status label including post count" msgid "Switched (%s)" msgid_plural "Switched (%s)" @@ -6202,7 +3334,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a post count. -#: woocommerce-subscriptions.php:348 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:415 msgctxt "post status label including post count" msgid "Expired (%s)" msgid_plural "Expired (%s)" @@ -6210,94 +3342,3560 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a post count. -#: woocommerce-subscriptions.php:350 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:417 msgctxt "post status label including post count" msgid "Pending Cancellation (%s)" msgid_plural "Pending Cancellation (%s)" msgstr[0] "" msgstr[1] "" -#: woocommerce-subscriptions.php:390 -msgid "To enable automatic renewals for this subscription, you will first need to add a payment method." -msgstr "" - -#: woocommerce-subscriptions.php:390 -msgid "Would you like to add a payment method now?" -msgstr "" - -#. translators: placeholder is a number, this is for the teens -#. translators: placeholder is a number, numbers ending in 4-9, 0 -#: woocommerce-subscriptions.php:672 -#: woocommerce-subscriptions.php:689 -msgid "%sth" -msgstr "" - -#. translators: placeholder is a number, numbers ending in 1 -#: woocommerce-subscriptions.php:677 -msgid "%sst" -msgstr "" - -#. translators: placeholder is a number, numbers ending in 2 -#: woocommerce-subscriptions.php:681 -msgid "%snd" -msgstr "" - -#. translators: placeholder is a number, numbers ending in 3 -#: woocommerce-subscriptions.php:685 -msgid "%srd" -msgstr "" - -#. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, leads to plugins.php in admin -#: woocommerce-subscriptions.php:724 -msgid "%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce plugin%4$s must be active for WooCommerce Subscriptions to work. Please %5$sinstall & activate WooCommerce »%6$s" -msgstr "" - -#. translators: 1$-2$: opening and closing tags, 3$: minimum supported WooCommerce version, 4$-5$: opening and closing link tags, leads to plugin admin -#: woocommerce-subscriptions.php:727 -msgid "%1$sWooCommerce Subscriptions is inactive.%2$s This version of Subscriptions requires WooCommerce %3$s or newer. Please %4$supdate WooCommerce to version %3$s or newer »%5$s" -msgstr "" - -#: woocommerce-subscriptions.php:758 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:466 msgid "Variable Subscription" msgstr "" -#. translators: 1-2: opening/closing tags, 3: Subscriptions version. -#: woocommerce-subscriptions.php:855 -msgid "%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce Subscriptions%2$s comes with that plugin's functionality packaged into the core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to avoid any conflicts." +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:515 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:36 +msgctxt "short for documents" +msgid "Docs" msgstr "" -#: woocommerce-subscriptions.php:858 -msgid "Installed Plugins" -msgstr "" - -#. translators: 1$-2$: opening and closing tags. 3$-4$: opening and closing link tags for learn more. Leads to duplicate site article on docs. 5$-6$: Opening and closing link to production URL. 7$: Production URL . -#: woocommerce-subscriptions.php:927 -msgid "It looks like this site has moved or is a duplicate site. %1$sWooCommerce Subscriptions%2$s has disabled automatic payments and subscription related emails on this site to prevent duplicate payments from a staging or test environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be the site's URL. %3$sLearn more »%4$s." -msgstr "" - -#: woocommerce-subscriptions.php:936 -msgid "Quit nagging me (but don't enable automatic payments)" -msgstr "" - -#: woocommerce-subscriptions.php:941 -msgid "Enable automatic payments" -msgstr "" - -#: woocommerce-subscriptions.php:1147 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:516 msgid "Support" msgstr "" #. translators: placeholders are opening and closing tags. Leads to docs on version 2 -#: woocommerce-subscriptions.php:1230 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:539 msgid "Warning! Version 2.0 is a major update to the WooCommerce Subscriptions extension. Before updating, please create a backup, update all WooCommerce extensions and test all plugins, custom code and payment gateways with version 2.0 on a staging site. %1$sLearn more about the changes in version 2.0 »%2$s" msgstr "" +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:134 +msgid "Sign Up Fee Discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:135 +msgid "Sign Up Fee % Discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:136 +msgid "Recurring Product Discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:137 +msgid "Recurring Product % Discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:446 +msgid "Sorry, this coupon is only valid for an initial payment and the cart does not require an initial payment." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:452 +msgid "Sorry, this coupon is only valid for new subscriptions." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:457 +msgid "Sorry, this coupon is only valid for subscription products." +msgstr "" + +#. translators: 1$: coupon code that is being removed +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:463 +msgid "Sorry, the \"%1$s\" coupon is only valid for renewals." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:468 +msgid "Sorry, this coupon is only valid for subscription products with a sign-up fee." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:494 +msgid "Sorry, recurring coupons can only be applied to subscriptions or subscription orders." +msgstr "" + +#. translators: placeholder is coupon code +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:498 +msgid "Sorry, \"%s\" can only be applied to subscription parent orders which contain a product with signup fees." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:501 +msgid "Sorry, only recurring coupons can be applied to subscriptions." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:674 +msgid "Renewal % discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:675 +msgid "Renewal product discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:676 +msgid "Renewal cart discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:677 +msgid "Initial payment discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:694 +msgid "Renewal Discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php:697 +#: vendor/woocommerce/subscriptions-core/build/index.js:6 +msgid "Discount" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:181 +msgid "Subscription Product length." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:187 +msgid "Subscription Product trial period." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:194 +msgid "Subscription Product trial interval." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:200 +msgid "Subscription Product signup fees." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:206 +msgid "Subscription Product signup fees taxes." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:212 +msgid "Indicates whether this product is being used to resubscribe the customer to an existing, expired subscription." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:221 +msgid "Indicates whether this product a subscription update, downgrade, cross grade or none of the above." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:230 +msgid "Synchronization data for the subscription." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:234 +msgid "Synchronization day if subscription is annual." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:238 +msgid "Synchronization month if subscription is annual." +msgstr "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:293 +msgid "Shipment every %d year" +msgid_plural "Shipment every %d years" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:293 +msgid "Yearly Shipment" +msgstr "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:297 +msgid "Shipment every %d month" +msgid_plural "Shipment every %d months" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:297 +msgid "Monthly Shipment" +msgstr "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:301 +msgid "Shipment every %d week" +msgid_plural "Shipment every %d weeks" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:301 +msgid "Weekly Shipment" +msgstr "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:305 +msgid "Shipment every %d day" +msgid_plural "Shipment every %d days" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:305 +msgid "Daily Shipment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:430 +msgid "Subscription key" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:455 +msgid "Subscription length." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:461 +msgid "Cart total amounts provided using the smallest unit of the currency." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:467 +msgid "Total price of items in the cart." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:473 +msgid "Total tax on items in the cart." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:479 +msgid "Total price of any applied fees." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:485 +msgid "Total tax on fees." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:491 +msgid "Total discount from applied coupons." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:497 +msgid "Total tax removed due to discount from applied coupons." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:503 +msgid "Total price of shipping. If shipping has not been calculated, a null response will be sent." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:509 +msgid "Total tax on shipping. If shipping has not been calculated, a null response will be sent." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:515 +msgid "Total price the customer will pay." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:521 +msgid "Total tax applied to items and shipping." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:527 +msgid "Lines of taxes applied to items and shipping." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:535 +msgid "The name of the tax." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:541 +msgid "The amount of tax charged." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:550 +msgid "Currency code (in ISO format) for returned prices." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:556 +msgid "Currency symbol for the currency which can be used to format returned prices." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:562 +msgid "Currency minor unit (number of digits after the decimal separator) for returned prices." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:568 +msgid "Decimal separator for the currency which can be used to format returned prices." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:574 +msgid "Thousand separator for the currency which can be used to format returned prices." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:580 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:586 +msgid "Price prefix for the currency which can be used to format returned prices." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-frontend-scripts.php:51 +msgid "To enable automatic renewals for this subscription, you will first need to add a payment method." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-frontend-scripts.php:51 +msgid "Would you like to add a payment method now?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:87 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1917 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1935 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Subscription renewal payment due:" +msgstr "" + +#. translators: placeholder is an order note. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:124 +msgid "Error: Unable to create renewal order with note \"%s\"" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:134 +msgid "Manual renewal order awaiting customer payment." +msgstr "" + +#. translators: $1: order number, $2: error message +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:306 +msgid "Failed to activate subscription status for order #%1$s: %2$s" +msgstr "" + +#. translators: $1: order number, $2: error message +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:334 +msgid "Failed to update subscription status after order #%1$s was put on-hold: %2$s" +msgstr "" + +#. translators: $1: order number, $2: error message +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:362 +msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" +msgstr "" + +#. translators: $1: order number, $2: error message +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:390 +msgid "Failed to set subscription as expired for order #%1$s: %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:416 +msgid "Subscription sign up failed." +msgstr "" + +#. translators: $1: order number, $2: error message +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:426 +msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:500 +msgid "Error: Unable to create subscription. Please try again." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:522 +msgid "Error: Unable to add product to created subscription. Please try again." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:567 +msgid "Pending subscription created." +msgstr "" + +#. Translators: 1: The subscription ID number. 2: The current user's username. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:913 +msgid "The related subscription #%1$s has been deleted after the customer was deleted by %2$s." +msgstr "" + +#. Translators: Placeholder is the subscription ID number. +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:916 +msgid "The related subscription #%s has been deleted after the customer was deleted." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1062 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:230 +msgctxt "Subscription status" +msgid "Active" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1065 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:232 +msgctxt "Subscription status" +msgid "Cancelled" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1068 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:234 +msgctxt "Subscription status" +msgid "Expired" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1071 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:229 +msgctxt "Subscription status" +msgid "Pending" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1074 +msgctxt "Subscription status" +msgid "Failed" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1078 +msgctxt "Subscription status" +msgid "On-hold" +msgstr "" + +#. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. "Jan") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1830 +msgctxt "used in a select box" +msgid "%1$s-%2$s" +msgstr "" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd like +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1843 +msgid "%1$s%2$s, %3$s @ %4$s : %5$s" +msgstr "" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input. Change the order if you'd like +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1847 +msgid "%1$s%2$s, %3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1852 +msgid "Change" +msgstr "" + +#. translators: placeholder is subscription ID +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2185 +msgid "Failed sign-up for subscription %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2276 +msgid "Invalid security token, please reload the page and try again." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2280 +msgid "Only store managers can edit payment dates." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2284 +msgid "Please enter all date fields." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2309 +msgid "Date Changed" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:345 +msgid "Your subscription will be activated when payment clears." +msgid_plural "Your subscriptions will be activated when payment clears." +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholders are opening and closing link tags +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:352 +msgid "View the status of your subscription in %1$syour account%2$s." +msgid_plural "View the status of your subscriptions in %1$syour account%2$s." +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:415 +msgid "Subscription Relationship" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:435 +msgid "Renewal Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:437 +msgid "Resubscribe Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:439 +msgid "Parent Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:483 +msgid "Payment completed on order after subscription was cancelled." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:720 +msgid "All orders types" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:723 +msgctxt "An order type" +msgid "Original" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:724 +msgctxt "An order type" +msgid "Subscription Parent" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:725 +msgctxt "An order type" +msgid "Subscription Renewal" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:726 +msgctxt "An order type" +msgid "Subscription Resubscribe" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:727 +msgctxt "An order type" +msgid "Subscription Switch" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:728 +msgctxt "An order type" +msgid "Non-subscription" +msgstr "" + +#. translators: $1: opening link tag, $2: order number, $3: closing link tag +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:1031 +msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s." +msgstr "" + +#. translators: %1$s refers to the price. This string is meant to prefix another string below, e.g. "$5 now, and $5 on March 15th each year" +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:293 +msgid "%1$s now, and " +msgstr "" + +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday"). +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday") +#. translators: %1$: recurring amount (e.g. "$15"), %2$: subscription period (e.g. "month") (e.g. "$15 every 2nd month") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:302 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:116 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:201 +msgid "%1$s every %2$s" +msgstr "" + +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday"). +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:306 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:125 +msgid "%1$s every %2$s on %3$s" +msgstr "" + +#. translators: placeholder is recurring amount. +#. translators: placeholder is recurring amount +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:317 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:143 +msgid "%s on the last day of each month" +msgstr "" + +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:321 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:146 +msgid "%1$s on the %2$s of each month" +msgstr "" + +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month"). +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:330 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:162 +msgid "%1$s on the last day of every %2$s month" +msgstr "" + +#. translators: 1$: on the, 2$: day of every, 3$: month (e.g. "$10 on the 23rd day of every 2nd month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:337 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:165 +msgid "%1$s on the %2$s day of every %3$s month" +msgstr "" + +#. translators: 1$: on, 2$: , 3$: each year (e.g. "$15 on March 15th each year"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:349 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:178 +msgid "%1$s on %2$s %3$s each year" +msgstr "" + +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:357 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:187 +msgid "%1$s on %2$s %3$s every %4$s year" +msgstr "" + +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month"). +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:369 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:198 +msgid "%1$s / %2$s" +msgid_plural "%1$s every %2$s" +msgstr[0] "" +msgstr[1] "" + +#. translators: billing period (e.g. "every week"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:379 +msgid "every %s" +msgstr "" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years"). +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:389 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:209 +msgid "%1$s for %2$s" +msgstr "" + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years"), 2$: trial length (e.g.: "with 4 months free trial"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:395 +msgid "%1$s with %2$s free trial" +msgstr "" + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a $30 sign-up fee"). +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:400 +msgid "%1$s and a %2$s sign-up fee" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:977 +msgid "This variation can not be removed because it is associated with existing subscriptions. To remove this variation, please permanently delete any related subscriptions." +msgstr "" + +#. translators: placeholder is order ID +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:161 +msgid "Order %s created to record renewal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:181 +msgid "Subscription renewal orders cannot be cancelled." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:48 +msgid "Synchronise renewals" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:49 +msgid "Align the payment date for all customers who purchase this subscription to a specific day of the week or month." +msgstr "" + +#. translators: placeholder is a year (e.g. "2016") +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:51 +msgctxt "used in subscription product edit screen" +msgid "Align the payment date for this subscription to a specific day of the year. If the date has already taken place this year, the first payment will be processed in %s. Set the day to 0 to disable payment syncing for this product." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:199 +msgid "Synchronisation" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:202 +msgctxt "used in the general subscription options page" +msgid "Align subscription renewal to a specific day of the week, month or year. For example, the first day of the month. %1$sLearn more%2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:208 +msgid "Align Subscription Renewal Day" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:215 +msgid "Prorate First Renewal" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:216 +msgid "If a subscription is synchronised to a specific day of the week, month or year, charge a prorated amount for the subscription at the time of sign up." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:222 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (do not charge any recurring amount)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:223 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (charge the full recurring amount at sign-up)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:231 +msgid "Sign-up grace period" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:232 +msgctxt "there's a number immediately in front of this text" +msgid "days prior to Renewal Day" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:236 +msgid "Subscriptions created within this many days prior to the Renewal Day will not be charged at sign-up. Set to zero for all new Subscriptions to be charged the full recurring amount. Must be a positive number." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:305 +msgid "Month for Synchronisation" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:313 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-synchronisation.php:36 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-synchronisation.php:42 +msgctxt "input field placeholder for day field for annual subscriptions" +msgid "Day" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:744 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:761 +msgid "Do not synchronise" +msgstr "" + +#. translators: placeholder is a day of the week +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:769 +msgid "%s each week" +msgstr "" + +#. translators: placeholder is a number of day with language specific suffix applied (e.g. "1st", "3rd", "5th", etc...) +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:775 +msgid "%s day of the month" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:777 +msgid "Last day of the month" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:825 +msgid "Today!" +msgstr "" + +#. translators: placeholder is a date +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:832 +msgid "First payment prorated. Next payment: %s" +msgstr "" + +#. translators: placeholder is a date +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:835 +msgid "First payment: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php:79 +msgid "Related order caching is now handled by %1$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php:86 +msgid "Customer subscription caching is now handled by %1$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php:110 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php:240 +msgid "Customer subscription caching is now handled by %1$s and %2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php:127 +msgid "new related order methods in WCS_Related_Order_Store" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php:225 +msgid "Weekly" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-initial-payment.php:65 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:208 +msgid "That doesn't appear to be your order." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:223 +msgid "This order can no longer be paid because the corresponding subscription does not require payment at this time." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:244 +msgid "Complete checkout to renew your subscription." +msgstr "" + +#. translators: placeholder is an item name +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:327 +msgid "The %s product has been deleted and can no longer be renewed. Please choose a new product or contact us for assistance." +msgstr "" + +#. translators: %s is subscription's number +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:362 +msgid "Subscription #%s has not been added to the cart." +msgstr "" + +#. translators: %s is order's number +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:365 +msgid "Order #%s has not been added to the cart." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:404 +msgid "We couldn't find the original subscription for an item in your cart. The item was removed." +msgid_plural "We couldn't find the original subscriptions for items in your cart. The items were removed." +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:411 +msgid "We couldn't find the original renewal order for an item in your cart. The item was removed." +msgid_plural "We couldn't find the original renewal orders for items in your cart. The items were removed." +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:694 +msgid "All linked subscription items have been removed from the cart." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:723 +msgctxt "Used in WooCommerce by removed item notification: \"_All linked subscription items were_ removed. Undo?\" Filter for item title." +msgid "All linked subscription items were" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:1512 +msgctxt "The place order button text while renewing a subscription" +msgid "Renew subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:70 +msgid "There was an error with your request to resubscribe. Please try again." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:82 +msgid "You can not resubscribe to that subscription. Please contact us if you need assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:91 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:119 +msgid "Complete checkout to resubscribe." +msgstr "" + +#. translators: %s: order number. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:320 +msgid "Customer resubscribed in order #%s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php:338 +msgctxt "The place order button text while resubscribing to a subscription" +msgid "Resubscribe" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:123 +msgid "Please choose a valid payment gateway to change to." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:158 +msgid "Ignore this error" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php:46 +msgid "Limit subscription" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php:48 +msgid "Only allow a customer to have one subscription to this product. %1$sLearn more%2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php:50 +msgid "Do not limit" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php:51 +msgid "Limit to one active subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php:52 +msgid "Limit to one of any status" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:153 +msgid "Auto Renewal Toggle" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:154 +msgid "Display the auto renewal toggle" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:155 +msgid "Allow customers to turn on and off automatic renewals from their View Subscription page." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:110 +msgid "The deleted payment method was used for automatic subscription payments, we couldn't find an alternative token payment method token to change your subscriptions to." +msgstr "" + +#. translators: 1: deleted token, 2: new token. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:128 +msgctxt "used in subscription note" +msgid "Payment method meta updated after customer deleted a token from their My Account page. Payment meta changed from %1$s to %2$s" +msgstr "" + +#. translators: $1: the token/credit card label, 2$-3$: opening and closing strong and link tags +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:133 +msgid "The deleted payment method was used for automatic subscription payments. To avoid failed renewal payments in future the subscriptions using this payment method have been updated to use your %1$s. To change the payment method of individual subscriptions go to your %2$sMy Account > Subscriptions%3$s page." +msgstr "" + +#. translators: 1: token display name, 2: opening link tag, 4: closing link tag, 3: opening link tag. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:188 +msgid "Would you like to update your subscriptions to use this new payment method - %1$s?%2$sYes%4$s | %3$sNo%4$s" +msgstr "" + +#. translators: 1: previous token, 2: new token. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:229 +msgctxt "used in subscription note" +msgid "Payment method meta updated after customer changed their default token and opted to update their subscriptions. Payment meta changed from %1$s to %2$s" +msgstr "" + +#. translators: %1$s opening strong HTML tag, %2$s closing strong HTML tag. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:251 +msgid "That payment method cannot be deleted because it is linked to an automatic subscription. Please %1$sadd a payment method%2$s, before trying again." +msgstr "" + +#. translators: %1$s opening strong and em HTML tags, %2$s closing em HTML tag, %3$s closing strong HTML tag. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php:257 +msgid "That payment method cannot be deleted because it is linked to an automatic subscription. Please choose a %1$sdefault%2$s payment method%3$s, before trying again." +msgstr "" + +#. translators: 1$-2$: opening and closing tags. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-permalink-manager.php:91 +msgid "Error saving Subscriptions endpoints: %1$sSubscriptions%2$s, %1$sView subscription%2$s and %1$sSubscription payment method%2$s cannot be the same. The changes have been reverted." +msgstr "" + +#. translators: %s: invalid type of update argument. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-post-meta-cache-manager.php:199 +msgid "Invalid update type: %s. Post update types supported are \"add\" or \"delete\". Updates are done on post meta directly." +msgstr "" + +#. translators: placeholder is a page number. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:106 +msgid "Subscriptions (page %d)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:131 +msgid "My Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:288 +msgid "Endpoint for the My Account → Subscriptions page" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:296 +msgid "View subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:297 +msgid "Endpoint for the My Account → View Subscription page" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:305 +msgid "Subscription payment method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php:306 +msgid "Endpoint for the My Account → Change Subscription Payment Method page" +msgstr "" + +#. translators: %d: subscription ID. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:79 +msgctxt "hash before subscription ID" +msgid "Subscription #%d does not exist." +msgstr "" + +#. translators: 1$: product name, 2$: product id +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:114 +msgctxt "used in order note" +msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:119 +msgid "Your request to undo your previous action was unsuccessful." +msgstr "" + +#. translators: 1$: product name, 2$: product id +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:137 +msgctxt "used in order note" +msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" + +#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:140 +msgid "You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:176 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:107 +msgid "Security error. Please contact us if you need assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:180 +msgid "You cannot modify a subscription that does not belong to you." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:184 +msgid "You cannot remove an item that does not exist. " +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php:188 +msgid "The item was not removed because this Subscription's payment method does not support removing an item." +msgstr "" + +#. translators: 1-2: opening/closing
    tags - linked to staging site, 3: link to live site. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:41 +msgid "Payment processing skipped - renewal order created on %1$sstaging site%2$s under staging site lock. Live site is at %3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:84 +msgid "Subscription locked to Manual Renewal while the store is in staging mode. Payment method changes will take effect in live mode." +msgstr "" + +#. translators: placeholder is a payment method title. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:98 +msgid "Subscription locked to Manual Renewal while the store is in staging mode. Live payment method: %s" +msgstr "" + +#. translators: 1$-2$: opening and closing tags. 3$-4$: opening and closing link tags for learn more. Leads to duplicate site article on docs. 5$-6$: Opening and closing link to production URL. 7$: Production URL . +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:129 +msgid "It looks like this site has moved or is a duplicate site. %1$sWooCommerce Subscriptions%2$s has disabled automatic payments and subscription related emails on this site to prevent duplicate payments from a staging or test environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be the site's URL. %3$sLearn more »%4$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:142 +msgid "Quit nagging me (but don't enable automatic payments)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-staging.php:147 +msgid "Enable automatic payments" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-template-loader.php:105 +msgid "My Account" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:57 +msgctxt "order note left on subscription after user action" +msgid "Subscription reactivated by the subscriber from their account page." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:58 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been reactivated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:61 +msgid "You can not reactivate that subscription until paying to renew it. Please contact us if you need assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:67 +msgctxt "order note left on subscription after user action" +msgid "Subscription put on hold by the subscriber from their account page." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:68 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been put on hold." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:71 +msgid "You can not suspend that subscription - the suspension limit has been reached. Please contact us if you need assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:76 +msgctxt "order note left on subscription after user action" +msgid "Subscription cancelled by the subscriber from their account page." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:77 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been cancelled." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:103 +msgid "That subscription does not exist. Please contact us if you need assistance." +msgstr "" + +#. translators: placeholder is subscription's new status, translated +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-user-change-status-handler.php:116 +msgid "That subscription can not be changed to %s. Please contact us if you need assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-customer-store-cached-cpt.php:56 +msgid "Generate Customer Subscription Cache" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-customer-store-cached-cpt.php:56 +msgid "This will generate the persistent cache for linking users with subscriptions. The caches will be generated overtime in the background (via Action Scheduler)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-customer-store-cached-cpt.php:57 +msgid "Delete Customer Subscription Cache" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-customer-store-cached-cpt.php:57 +msgid "This will clear the persistent cache of all of subscriptions stored against users in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as queries to find a given user's subscriptions are run." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "Generate Related Order Cache" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "This will generate the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. The caches will be generated overtime in the background (via Action Scheduler)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "Delete Related Order Cache" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "This will clear the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as related order queries are run." +msgstr "" + #. translators: placeholder is Subscriptions version number. -#: woocommerce-subscriptions.php:1246 +#: vendor/woocommerce/subscriptions-core/includes/deprecated/deprecation-handlers/class-wc-subscriptions-deprecation-handler.php:271 msgid "Warning! You are running version %s of WooCommerce Subscriptions plugin code but your database has been upgraded to Subscriptions version 2.0. This will cause major problems on your store." msgstr "" #. translators: opening/closing tags - linked to ticket form. -#: woocommerce-subscriptions.php:1248 +#: vendor/woocommerce/subscriptions-core/includes/deprecated/deprecation-handlers/class-wc-subscriptions-deprecation-handler.php:273 msgid "Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer immediately. If you need assistance, after upgrading to Subscriptions v2.0, please %1$sopen a support ticket%2$s." msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:26 +msgid "Cancelled Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:27 +msgid "Cancelled Subscription emails are sent when a customer's subscription is cancelled (either by a store manager, or the customer)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:29 +msgid "Subscription Cancelled" +msgstr "" + +#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:31 +msgctxt "default email subject for cancelled emails sent to the admin" +msgid "[%s] Subscription Cancelled" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:143 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:210 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:141 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:141 +msgctxt "an email notification" +msgid "Enable/Disable" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:145 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:212 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:143 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:143 +msgid "Enable this email notification" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:149 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:147 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:147 +msgctxt "of an email" +msgid "Recipient(s)" +msgstr "" + +#. translators: placeholder is admin email +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:152 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:150 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:150 +msgid "Enter recipients (comma separated) for this email. Defaults to %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:157 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:155 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:155 +msgctxt "of an email" +msgid "Subject" +msgstr "" + +#. translators: %s: default e-mail subject. +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:160 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:158 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:158 +msgid "This controls the email subject line. Leave blank to use the default subject: %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:165 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:163 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:163 +msgctxt "Name the setting that controls the main heading contained within the email notification" +msgid "Email Heading" +msgstr "" + +#. translators: %s: default e-mail heading. +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:168 +msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:173 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:171 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:171 +msgctxt "text, html or multipart" +msgid "Email type" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:175 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:173 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:173 +msgid "Choose which format of email to send." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:179 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:177 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:177 +msgctxt "email type" +msgid "Plain text" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:180 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:178 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:178 +msgctxt "email type" +msgid "HTML" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:181 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:179 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:179 +msgctxt "email type" +msgid "Multipart" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-renewal-order.php:25 +msgid "Completed Renewal Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-renewal-order.php:26 +msgid "Renewal order complete emails are sent to the customer when a subscription renewal order is marked complete and usually indicates that the item for that renewal period has been shipped." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-renewal-order.php:29 +msgctxt "Default email heading for email to customer on completed renewal order" +msgid "Your renewal order is complete" +msgstr "" + +#. translators: $1: {blogname}, $2: {order_date}, variables that will be substituted when email is sent out +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-renewal-order.php:31 +msgctxt "Default email subject for email to customer on completed renewal order" +msgid "Your %1$s renewal order from %2$s is complete" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-renewal-order.php:38 +msgctxt "Default email heading for email with downloadable files in it" +msgid "Your subscription renewal order is complete - download your files" +msgstr "" + +#. translators: $1: {blogname}, $2: {order_date}, variables will be substituted when email is sent out +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-renewal-order.php:40 +msgctxt "Default email subject for email with downloadable files in it" +msgid "Your %1$s subscription renewal order from %2$s is complete - download your files" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-switch-order.php:26 +msgid "Subscription Switch Complete" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-switch-order.php:27 +msgid "Subscription switch complete emails are sent to the customer when a subscription is switched successfully." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-switch-order.php:30 +msgid "Your subscription change is complete" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-switch-order.php:31 +msgid "Your {blogname} subscription change from {order_date} is complete" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-switch-order.php:38 +msgid "Your subscription change is complete - download your files" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-completed-switch-order.php:39 +msgid "Your {blogname} subscription change from {order_date} is complete - download your files" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:23 +msgid "On-hold Renewal Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:24 +msgid "This is an order notification sent to customers containing order details after a renewal order is placed on-hold." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:25 +msgid "Your {blogname} renewal order has been received!" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:26 +msgid "Thank you for your renewal order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:40 +msgid "Customer Renewal Invoice" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:41 +msgid "Sent to a customer when the subscription is due for renewal and the renewal requires a manual payment, either because it uses manual renewals or the automatic recurring payment failed for the initial attempt and all automatic retries (if any). The email contains renewal order information and payment links." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:48 +msgid "Invoice for renewal order {order_number} from {order_date}" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:49 +msgid "Invoice for renewal order {order_number}" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:26 +msgid "Expired Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:27 +msgid "Expired Subscription emails are sent when a customer's subscription expires." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:29 +msgid "Subscription Expired" +msgstr "" + +#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:31 +msgctxt "default email subject for expired emails sent to the admin" +msgid "[%s] Subscription Expired" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:78 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:78 +msgid "Subscription argument passed in is not an object." +msgstr "" + +#. translators: %s: default e-mail heading. +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:166 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:166 +msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-renewal-order.php:22 +msgid "New Renewal Order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-renewal-order.php:23 +msgid "New renewal order emails are sent when a subscription renewal payment is processed." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-renewal-order.php:25 +msgid "New subscription renewal order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-renewal-order.php:26 +msgid "[{blogname}] New subscription renewal order ({order_number}) - {order_date}" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-switch-order.php:22 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-switch-order.php:25 +msgid "Subscription Switched" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-switch-order.php:23 +msgid "Subscription switched emails are sent when a customer switches a subscription." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-new-switch-order.php:26 +msgid "[{blogname}] Subscription Switched ({order_number}) - {order_date}" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:26 +msgid "Suspended Subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:27 +msgid "Suspended Subscription emails are sent when a customer manually suspends their subscription." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:29 +msgid "Subscription Suspended" +msgstr "" + +#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:31 +msgctxt "default email subject for suspended emails sent to the admin" +msgid "[%s] Subscription Suspended" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-processing-renewal-order.php:24 +msgid "Processing Renewal order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-processing-renewal-order.php:25 +msgid "This is an order notification sent to the customer after payment for a subscription renewal order is completed. It contains the renewal order details." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-processing-renewal-order.php:28 +msgid "Thank you for your order" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-processing-renewal-order.php:29 +msgid "Your {blogname} renewal order receipt from {order_date}" +msgstr "" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-core-payment-gateways.php:178 +msgid "Sorry, it seems there are no available payment methods which support subscriptions. Please see %1$sEnabling Payment Gateways for Subscriptions%2$s if you require assistance." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-core-payment-gateways.php:180 +msgid "Sorry, it seems there are no available payment methods which support subscriptions. Please contact us if you require assistance or wish to make alternate arrangements." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-core-payment-gateways.php:271 +msgid "Supported features:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-core-payment-gateways.php:274 +msgid "Subscription features:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-core-payment-gateways.php:278 +msgid "Change payment features:" +msgstr "" + +#. Translators: placeholder is a 0 price formatted with the the store's currency and decimal settings. +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-gateway-restrictions-manager.php:44 +msgid "Please enter a price greater than %s." +msgstr "" + +#. Translators: Placeholder is a localized price string (eg. $1.00). +#: vendor/woocommerce/subscriptions-core/includes/gateways/class-wc-subscriptions-gateway-restrictions-manager.php:64 +msgid "Warning! Your store cannot create subscriptions less than %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:220 +msgid "Unable to find order for PayPal billing agreement." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:282 +msgid "An error occurred, please try again or try an alternate form of payment." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:362 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:320 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:336 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:384 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:150 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:156 +msgctxt "hash before the order number. Used as a character to remove from the actual order number" +msgid "#" +msgstr "" + +#. translators: placeholders are PayPal API error code and PayPal API error message +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:386 +msgid "PayPal API error: (%1$d) %2$s" +msgstr "" + +#. translators: placeholder is PayPal transaction status message +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:391 +msgid "PayPal Transaction Held: %s" +msgstr "" + +#. translators: placeholder is PayPal transaction status message +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:403 +msgid "PayPal payment declined: %s" +msgstr "" + +#. translators: placeholder is a transaction ID. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:407 +msgid "PayPal payment approved (ID: %s)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:460 +msgid "" +"Are you sure you want to change the payment method from PayPal standard?\n" +"\n" +"This will suspend the subscription at PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/class-wcs-paypal.php:626 +msgctxt "used in User Agent data sent to PayPal to help identify where a payment came from" +msgid "WooCommerce Subscriptions PayPal" +msgstr "" + +#. translators: $1 and $2 are opening and closing strong tags, respectively. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:63 +msgid "It is %1$sstrongly recommended you do not change the Receiver Email address%2$s if you have active subscriptions with PayPal. Doing so can break existing subscriptions." +msgstr "" + +#. translators: placeholders are opening and closing link tags. 1$-2$: to docs on woocommerce, 3$-4$ to gateway settings on the site +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:114 +msgid "PayPal is inactive for subscription transactions. Please %1$sset up the PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for Subscriptions." +msgstr "" + +#. translators: opening/closing tags - links to documentation. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:126 +msgid "%1$sPayPal Reference Transactions are not enabled on your account%2$s, some subscription management features are not enabled. Please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" + +#. translators: opening/closing tags - links to documentation. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:130 +msgid "%1$sPayPal Reference Transactions are not enabled on your account%2$s. If you wish to use PayPal Reference Transactions with Subscriptions, please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" + +#. translators: placeholders are opening and closing strong tags. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:152 +msgid "%1$sPayPal Reference Transactions are enabled on your account%2$s. All subscription management features are now enabled. Happy selling!" +msgstr "" + +#. translators: placeholders are link opening and closing tags. 1$-2$: to gateway settings, 3$-4$: support docs on woocommerce.com +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:163 +msgid "There is a problem with PayPal. Your API credentials may be incorrect. Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s." +msgstr "" + +#. translators: placeholders are opening and closing link tags. 1$-2$: docs on woocommerce, 3$-4$: dismiss link +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:176 +msgid "There is a problem with PayPal. Your PayPal account is issuing out-of-date subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:198 +msgid "Ignore this error (not recommended)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:203 +msgid "Open a ticket" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:290 +msgid "PayPal Subscription ID:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:316 +msgid "Enable PayPal Standard for Subscriptions" +msgstr "" + +#. translators: Placeholders are the opening and closing link tags. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:324 +msgid "Before enabling PayPal Standard for Subscriptions, please note, when using PayPal Standard, customers are locked into using PayPal Standard for the life of their subscription, and PayPal Standard has a number of limitations. Please read the guide on %1$swhy we don't recommend PayPal Standard%2$s for Subscriptions before choosing to enable this option." +msgstr "" + +#. translators: placeholder is blogname +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:71 +msgctxt "data sent to paypal" +msgid "Orders with %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:279 +msgid "Total Discount" +msgstr "" + +#. translators: placeholder is blogname +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:306 +msgid "%s - Order" +msgstr "" + +#. translators: 1$: new status (e.g. "Cancel"), 2$: blog name +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:416 +msgctxt "data sent to paypal" +msgid "%1$s subscription event triggered at %2$s" +msgstr "" + +#. translators: %s: product SKU. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:536 +msgid "SKU: %s" +msgstr "" + +#. translators: placeholder is localised datetime +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119 +msgid "expected clearing date %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:136 +msgctxt "used in api error message if there is no severity code from PayPal" +msgid "Error" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:138 +msgctxt "used in api error message if there is no long message" +msgid "Unknown error" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:150 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php:14 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-tax-html.php:9 +msgctxt "no information about something" +msgid "N/A" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php:94 +msgid "Billing agreement cancelled at PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:275 +msgctxt "when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method" +msgid "IPN subscription payment method changed to PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:279 +msgid "IPN subscription sign up completed." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:332 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:417 +msgid "IPN subscription payment completed." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:379 +msgid "IPN subscription failing payment method changed." +msgstr "" + +#. translators: placeholder is payment status (e.g. "completed") +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:427 +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:436 +msgctxt "used in order note" +msgid "IPN subscription payment %s." +msgstr "" + +#. translators: 1: payment status (e.g. "completed"), 2: pending reason. +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:440 +msgctxt "used in order note" +msgid "IPN subscription payment %1$s for reason: %2$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:469 +msgid "IPN subscription suspended." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:492 +msgid "IPN subscription cancelled." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:508 +msgid "IPN subscription payment failure." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:646 +msgid "Invalid PayPal IPN Payload: unable to find matching subscription." +msgstr "" + +#. translators: 1$: subscription ID, 2$: names of items, comma separated +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:75 +msgctxt "item name sent to paypal" +msgid "Subscription %1$s - %2$s" +msgstr "" + +#. translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma separated +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:78 +msgctxt "item name sent to paypal" +msgid "Subscription %1$s (Order %2$s) - %3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php:271 +msgid "Subscription changed from PayPal Standard to PayPal Reference Transactions via customer initiated switch. The PayPal Standard subscription has been suspended." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42 +msgid "Subscription cancelled with PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:53 +msgid "Subscription suspended with PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:66 +msgid "Subscription reactivated with PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:113 +msgid "PayPal API error - credentials are incorrect." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:18 +msgid "A fatal error has occurred while processing a recent subscription payment with PayPal. Please %1$sopen a new ticket at WooCommerce Support%3$s immediately to get this resolved. %2$sLearn more »%3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:29 +msgid "To resolve this as quickly as possible, please create a %1$stemporary administrator account%3$s with the user email woologin@woocommerce.com and share the credentials with us via %2$sQuickForget.com%3$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:36 +msgid "Last recorded error:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:46 +msgid "To see the full error, view the %1$s log file from the %2$sWooCommerce logs screen.%3$s." +msgstr "" + +#. Translators: %s subscription number. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-erasers.php:71 +msgid "Removed personal data from subscription %s." +msgstr "" + +#. Translators: %s subscription number. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-erasers.php:75 +msgid "Personal data within subscription %s has been retained." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-erasers.php:189 +msgid "Personal data removed." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:77 +msgid "Subscription Number" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:78 +msgid "Created Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:79 +msgid "Recurring Total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:80 +msgid "Subscription Items" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:81 +msgid "IP Address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:82 +msgid "Browser User Agent" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:83 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:281 +msgid "Billing Address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:84 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:280 +msgid "Shipping Address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:85 +msgid "Phone Number" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy-exporters.php:86 +msgid "Email Address" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:43 +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:44 +msgid "Subscriptions Data" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:92 +msgid "By using WooCommerce Subscriptions, you may be storing personal data and depending on which third-party payment processors you’re using to take subscription payments, you may be sharing personal data with external sources." +msgstr "" + +#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:94 +msgid "What we collect and store" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:95 +msgid "For the purposes of processing recurring subscription payments, we store the customer's name, billing address, shipping address, email address, phone number and credit card/payment details." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:96 +msgid "What we share with others" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:97 +msgid "What personal information your store shares with external sources depends on which third-party payment processor plugins you are using to collect subscription payments. We recommend that you consult with their privacy policies to inform this section of your privacy policy." +msgstr "" + +#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:99 +msgid "If you are using PayPal Standard or PayPal Reference transactions please see the %1$sPayPal Privacy Policy%2$s for more details." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:109 +msgid "Cancel and remove personal data" +msgstr "" + +#. translators: %d: number of subscriptions affected. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:176 +msgid "Removed personal data from %d subscription." +msgid_plural "Removed personal data from %d subscriptions." +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholders are opening and closing tags. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:195 +msgid "%1$sNote:%2$s Orders which are related to subscriptions will not be included in the orders affected by these settings." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:215 +msgid "account erasure request" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:221 +msgid "Remove personal data from subscriptions" +msgstr "" + +#. Translators: %s URL to erasure request screen. +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:223 +msgid "When handling an %s, should personal data within subscriptions be retained or removed?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:232 +msgid "Retain ended subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:233 +msgid "Retain ended subscriptions and their related orders for a specified duration before anonymizing the personal data within them." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:236 +msgid "N/A" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:277 +msgid "Customers with a subscription are excluded from this setting." +msgstr "" + +#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 & 1.5") +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:355 +msgid "Database updated to version %s" +msgstr "" + +#. translators: placeholder is number of upgraded subscriptions +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:363 +msgctxt "used in the subscriptions upgrader" +msgid "Marked %s subscription products as \"sold individually\"." +msgstr "" + +#. translators: 1$: number of action scheduler hooks upgraded, 2$: "{execution_time}", will be replaced on front end with actual time +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:372 +msgid "Migrated %1$s subscription related hooks to the new scheduler (in %2$s seconds)." +msgstr "" + +#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}", will be replaced on front end with actual time it took +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:384 +msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)." +msgstr "" + +#. translators: placeholder is "{time_left}", will be replaced on front end with actual time +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:387 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:433 +msgctxt "Message that gets sent to front end." +msgid "Estimated time left (minutes:seconds): %s" +msgstr "" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, 4$: break tag +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:397 +msgid "Unable to upgrade subscriptions.%4$sError: %1$s%4$sPlease refresh the page and try again. If problem persists, %2$scontact support%3$s." +msgstr "" + +#. translators: placeholder is the number of subscriptions repaired +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:412 +msgctxt "Repair message that gets sent to front end." +msgid "Repaired %d subscriptions with incorrect dates, line tax data or missing customer notes." +msgstr "" + +#. translators: placeholder is number of subscriptions that were checked and did not need repairs. There's a space at the beginning! +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:418 +msgctxt "Repair message that gets sent to front end." +msgid " %d other subscription was checked and did not need any repairs." +msgid_plural "%d other subscriptions were checked and did not need any repairs." +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is "{execution_time}", which will be replaced on front end with actual time +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:422 +msgctxt "Repair message that gets sent to front end." +msgid "(in %s seconds)" +msgstr "" + +#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL languages. +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:425 +msgctxt "The assembled repair message that gets sent to front end." +msgid "%1$s%2$s %3$s" +msgstr "" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, 4$: break tag +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:444 +msgctxt "Error message that gets sent to front end when upgrading Subscriptions" +msgid "Unable to repair subscriptions.%4$sError: %1$s%4$sPlease refresh the page and try again. If problem persists, %2$scontact support%3$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:648 +msgid "Welcome to WooCommerce Subscriptions 2.1" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:648 +msgid "About WooCommerce Subscriptions" +msgstr "" + +#. translators: 1-2: opening/closing tags, 3-4: opening/closing tags linked to ticket form. +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:879 +msgid "%1$sWarning!%2$s We discovered an issue in %1$sWooCommerce Subscriptions 2.3.0 - 2.3.2%2$s that may cause your subscription renewal order and customer subscription caches to contain invalid data. For information about how to update the cached data, please %3$sopen a new support ticket%4$s." +msgstr "" + +#. translators: 1-2: opening/closing tags, 3: active version of Subscriptions, 4: current version of Subscriptions, 5-6: opening/closing tags linked to ticket form, 7-8: opening/closing tags linked to documentation. +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wc-subscriptions-upgrader.php:958 +msgid "%1$sWarning!%2$s It appears that you have downgraded %1$sWooCommerce Subscriptions%2$s from %3$s to %4$s. Downgrading the plugin in this way may cause issues. Please update to %3$s or higher, or %5$sopen a new support ticket%6$s for further assistance. %7$sLearn more »%8$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wcs-repair-suspended-paypal-subscriptions.php:51 +msgid "Subscription suspended by Database repair script. This subscription was suspended via PayPal." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/class-wcs-upgrade-2-2-7.php:60 +msgid "Subscription end date in the past" +msgstr "" + +#. translators: placeholder is Subscription version string ('2.3') +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/update-welcome-notice.php:2 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:23 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:22 +msgid "Thank you for updating to the latest version of WooCommerce Subscriptions." +msgstr "" + +#. translators: placeholder $1 is the Subscription version string ('2.3'), $2-3 are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/update-welcome-notice.php:5 +msgid "Version %1$s brings some new improvements requested by store managers just like you (and possibly even by %2$syou%3$s)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/update-welcome-notice.php:6 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:25 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:24 +msgid "We hope you enjoy it!" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/update-welcome-notice.php:8 +msgid "What's new?" +msgstr "" + +#. translators: placeholder is Subscription version string ('2.3') +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/update-welcome-notice.php:16 +msgid "Want to know more about Subscriptions %s?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:20 +msgid "Welcome to Subscriptions 2.0" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:24 +msgid "Version 2.0 has been in development for more than a year. We've reinvented the extension to take into account 3 years of feedback from store managers." +msgstr "" + +#. translators: placeholder is version number +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:31 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:30 +msgid "Version %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:42 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:41 +msgid "Check Out What's New" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:51 +msgid "Multiple Subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:52 +msgid "It's now easier for your customers to buy more subscriptions!" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:53 +msgid "Customers can now purchase different subscription products in one transaction. The products can bill on any schedule and have any combination of sign-up fees and/or free trials." +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:56 +msgid "Learn more about the new %smultiple subscriptions%s feature." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:68 +msgid "New Add/Edit Subscription Screen" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:69 +msgid "Subscriptions v2.0 introduces a new administration interface to add or edit a subscription. You can make all the familiar changes, like modifying recurring totals or subscription status. You can also make some new modifications, like changing the expiration date, adding a shipping cost or adding a product line item." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:72 +msgid "The new interface is also built on the existing %sEdit Order%s screen. If you've ever modified an order, you already know how to modify a subscription." +msgstr "" + +#. translators: placeholers are link tags: 1$-2$ new subscription page, 3$-4$: docs on woocommerce.com +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:76 +msgid "%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new interface." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:87 +msgid "New View Subscription Page" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:91 +msgid "Your customers can now view the full details of a subscription, including line items, billing and shipping address, billing schedule and renewal orders, from a special %sMy Account > View Subscription%s page." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:93 +msgid "This new page is also where the customer can suspend or cancel their subscription, change payment method, change shipping address or upgrade/downgrade an item." +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:97 +msgid "Learn more about the new %sView Subscription page%s." +msgstr "" + +#. translators: placeholders are for opening and closing link () tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:111 +msgid "By default, adding new files to an existing subscription product will automatically provide active subscribers with access to the new files. However, now you can enable a %snew content dripping setting%s to provide subscribers with access to new files only after the next renewal payment." +msgstr "" + +#. translators: placeholders are for opening and closing link () tags +#. translators: placeholders are opening and closing anchor tags linking to documentation +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:115 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:128 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:141 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:120 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:131 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:142 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:170 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:191 +msgid "%sLearn more »%s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:121 +msgctxt "h3 on the About Subscriptions page for this new feature" +msgid "Change Payment Method" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:124 +msgid "For a store manager to change a subscription from automatic to manual renewal payments (or manual to automatic) with Subscriptions v1.5, the database needed to be modified directly. Subscriptions now provides a way for payment gateways to allow you to change that from the new %sEdit Subscription%s interface." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:134 +msgid "Change Trial and End Dates" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:137 +msgid "It was already possible to change a subscription's next payment date, but some store managers wanted to provide a customer with an extended free trial or add an extra month to the expiration date. Now you can change all of these dates from the %sEdit Subscription%s screen." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:150 +msgid "And much more..." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:157 +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:151 +msgid "Peek Under the Hood for Developers" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:158 +msgid "Subscriptions 2.0 introduces a new architecture built on the WooCommerce Custom Order Types API." +msgstr "" + +#. translators: placeholders are opening and closing code tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:164 +msgid "New %sshop_subscription%s Post Type" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:166 +msgid "By making a subscription a Custom Order Type, a subscription is also now a custom post type. This makes it faster to query subscriptions and it uses a database schema that is as scalable as WordPress posts and pages." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:169 +msgid "Developers can also now use all the familiar WordPress functions, like %sget_posts()%s, to query or modify subscription data." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:175 +msgid "New %sWC_Subscription%s Object" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:177 +msgid "Subscriptions 2.0 introduces a new object for working with a subscription at the application level. The cumbersome APIs for retrieving or modifying a subscription's data are gone!" +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:180 +msgid "Because the %sWC_Subscription%s class extends %sWC_Order%s, you can use its familiar methods, like %s$subscription->update_status()%s or %s$subscription->get_total()%s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:184 +msgid "REST API Endpoints" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:185 +msgid "We didn't just improve interfaces for humans, we also improved them for computers. Your applications can now create, read, update or delete subscriptions via RESTful API endpoints." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:188 +msgid "Want to list all the subscriptions on a site? Get %sexample.com/wc-api/v2/subscriptions/%s. Want the details of a specific subscription? Get %s/wc-api/v2/subscriptions//%s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about-2-0.php:194 +msgid "Go to WooCommerce Subscriptions Settings" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:19 +msgid "Welcome to Subscriptions 2.1!" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:23 +msgid "Version 2.1 introduces some great new features requested by store managers just like you (and possibly even by %syou%s)." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:35 +msgctxt "short for documents" +msgid "Documentation" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:49 +msgid "Subscription Reports" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:50 +msgid "How many customers stay subscribed for more than 6 months? What is the average lifetime value of your subscribers? How much renewal revenue will your store earn next month?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:51 +msgid "These are important questions for any subscription commerce business." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:52 +msgid "Prior to Subscriptions 2.1, they were not easy to answer. Subscriptions 2.1 introduces new reports to answer these questions, and many more." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:54 +msgid "View Reports" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:55 +msgctxt "learn more link to subscription reports documentation" +msgid "Learn More" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:67 +msgid "Automatic Failed Payment Retry" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:68 +msgid "Failed recurring payments can now be retried automatically. This helps recover revenue that would otherwise be lost due to payment methods being declined only temporarily." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:69 +msgid "By default, Subscriptions will retry the payment 5 times over 7 days. The rules that control the retry system can be modified to customise:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:71 +msgid "the total number of retry attempts" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:72 +msgid "how long to wait between retry attempts" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:73 +msgid "emails sent to the customer and store manager" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:74 +msgid "the status applied to the renewal order and subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:76 +msgid "The retry system is disabled by default. To enable it, visit the Subscriptions settings administration screen." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:78 +msgid "Enable Automatic Retry" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:79 +msgctxt "learn more link to failed payment retry documentation" +msgid "Learn More" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:90 +msgid "New Subscription Emails" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:91 +msgid "Subscriptions 2.1 also introduces a number of new emails to notify you when:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:93 +msgid "a customer suspends a subscription" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:94 +msgid "an automatic payment fails" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:95 +msgid "a subscription expires" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:97 +msgid "These emails can be enabled, disabled and customised under the %sWooCommerce > Settings > Emails%s administration screen." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:99 +msgid "View Email Settings" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:100 +msgctxt "learn more link to subscription emails documentation" +msgid "Learn More" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:108 +msgid "But wait, there's more!" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:109 +msgid "That's not all we've working on for the last 12 months when it comes to Subscriptions. We've also released mini-extensions to help you get the most from your subscription store." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:115 +msgid "Subscription Gifting" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:116 +msgid "What happens when a customer wants to purchase a subscription product for someone else?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:117 +msgid "The Gifting extension makes it possible for one person to purchase a subscription product for someone else. It then shares control of the subscription between the purchaser and recipient, allowing both to manage the subscription over its lifecycle." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:126 +msgctxt "h3 on the About Subscriptions page for this new feature" +msgid "Import/Export Subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:127 +msgid "Import subscriptions to WooCommerce via CSV, or export your subscriptions from WooCommerce to a CSV with the WooCommerce Subscriptions Importer/Exporter extension." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:128 +msgid "This free extension makes it possible to migrate subscribers from 3rd party systems to WooCommerce. It also makes it possible to export your subscription data for analysis in spreadsheet tools or 3rd party apps." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:137 +msgid "Subscribe All the Things" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:138 +msgid "Want your customers to be able to subscribe to non-subscription products?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:139 +msgid "With WooCommerce Subscribe All the Things, they can! This experimental extension is exploring how to convert any product, including Product Bundles and Composite Products, into a subscription product. It also offers customers a way to subscribe to a cart of non-subscription products." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:157 +msgid "Customise Retry Rules" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:159 +msgid "The best part about the new automatic retry system is that the retry rules are completely customisable." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:162 +msgid "With the %s'wcs_default_retry_rules'%s filter, you can define a set of default rules to apply to all failed payments in your store." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:166 +msgid "To apply a specific rule based on certain conditions, like high value orders or an infrequent renewal schedule, you can use the retry specific %s'wcs_get_retry_rule'%s filter. This provides the ID of the renewal order for the failed payment, which can be used to find information about the products, subscription and totals to which the failed payment relates." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:174 +msgid "WP REST API Endpoints" +msgstr "" + +#. translators: $1: opening tag linking to WC API docs, $2: closing tag, $3: opening tag linking to WP API docs, $4: closing tag +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:177 +msgid "WooCommerce 2.6 added support for %1$sREST API%2$s endpoints built on WordPress core's %3$sREST API%4$s infrastructure." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:179 +msgid "Subscriptions 2.1 adds support for subscription data to this infrastructure." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:180 +msgid "Your applications can now create, read, update or delete subscriptions via RESTful API endpoints with the same design as the latest version of WooCommerce's REST API endpoints." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:183 +msgid "Want to list all the subscriptions on a site? Get %s/wp-json/wc/v1/subscriptions%s." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:187 +msgid "Want the details of a specific subscription? Get %s/wp-json/wc/v1/subscriptions//%s." +msgstr "" + +#. translators: placeholders are opening and closing code tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:197 +msgid "Honour Renewal Order Data" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:199 +msgid "In previous versions of Subscriptions, the subscription total was passed to payment gateways as the amount to charge for automatic renewal payments. This made it unnecessarily complicated to add one-time fees or discounts to a renewal." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:202 +msgid "Subscriptions 2.1 now passes the renewal order's total, making it possible to add a fee or discount to the renewal order with simple one-liners like %s$order->add_fee()%s or %s$order->add_coupon()%s." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:206 +msgid "Subscriptions also now uses the renewal order to setup the cart for %smanual renewals%s, making it easier to add products or discounts to a single renewal paid manually." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:212 +msgid "See the full guide to What's New in Subscriptions version 2.1 »" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-about.php:213 +msgid "Go to WooCommerce Subscriptions Settings »" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade-in-progress.php:24 +msgid "WooCommerce Subscriptions Update in Progress" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade-in-progress.php:30 +msgid "The Upgrade is in Progress" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade-in-progress.php:31 +msgid "The WooCommerce Subscriptions plugin is currently running its database upgrade routine." +msgstr "" + +#. translators: placeholder is number of seconds +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade-in-progress.php:34 +msgid "If you received a server error and reloaded the page to find this notice, please refresh the page in %s seconds and the upgrade routine will recommence without issues." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade-in-progress.php:36 +msgid "Rest assured, although the update process may take a little while, it is coded to prevent defects, your site is safe and will be up and running again, faster than ever, shortly." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:19 +msgid "WooCommerce Subscriptions Update" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:29 +msgid "Database Update Required" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:30 +msgid "The WooCommerce Subscriptions plugin has been updated!" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:33 +msgid "Before we send you on your way, we need to update your database to the newest version. If you do not have a recent backup of your site, %snow is the time to create one%s." +msgstr "" + +#. translators: 1$: number of subscriptions on site, 2$, lower estimate (minutes), 3$: upper estimate +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:38 +msgid "The full update process for the %1$d subscriptions on your site will take between %2$d and %3$d minutes." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:41 +msgid "The update process may take a little while, so please be patient." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:43 +msgid "Customers and other non-administrative users can browse and purchase from your store without interruption while the update is in progress." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:45 +msgctxt "text on submit button" +msgid "Update Database" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:49 +msgid "Update in Progress" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:50 +msgid "This page will display the results of the process as each batch of subscriptions is updated." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:51 +msgid "Please keep this page open until the update process completes. No need to refresh or restart the process." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:53 +msgid "Remember, although the update process may take a while, customers and other non-administrative users can browse and purchase from your store without interruption while the update is in progress." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:61 +msgid "Update Complete" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:62 +msgid "Your database has been updated successfully!" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:63 +msgid "Continue" +msgstr "" + +#. translators: $1: placeholder is number of weeks, 2$: path to the file +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:66 +msgid "To record the progress of the update a new log file was created. This file will be automatically deleted in %1$d weeks. If you would like to delete it sooner, you can find it here: %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:71 +msgid "Update Error" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/upgrades/templates/wcs-upgrade.php:72 +msgid "There was an error with the update. Please refresh the page and try again." +msgstr "" + +#. translators: %s: shipping method label. +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:98 +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:104 +msgid "Shipping via %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:237 +msgctxt "shipping method price" +msgid "Free" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:262 +msgid "[Remove]" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:292 +msgid "Free shipping coupon" +msgstr "" + +#. translators: placeholder is price string, denotes tax included in cart/order total +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:330 +msgctxt "includes tax" +msgid "(includes %s)" +msgstr "" + +#. translators: placeholder is a date +#: vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php:405 +msgid "First renewal: %s" +msgstr "" + +#. translators: placeholder is either subscription key or a subscription id, or, failing that, empty (e.g. "145_21" or "145") +#: vendor/woocommerce/subscriptions-core/includes/wcs-deprecated-functions.php:180 +msgid "Could not get subscription. Most likely the subscription key does not refer to a subscription. The key was: \"%s\"." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:41 +msgctxt "initial payment on a subscription" +msgid "up front" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount string (e.g. "£10 / month" ) +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:99 +msgid "%1$s %2$s then %3$s" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount string, 4$: payment day of the week (e.g. "$15 up front, then $10 every Wednesday") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:113 +msgid "%1$s %2$s then %3$s every %4$s" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front" ), 3$: recurring amount, 4$: interval (e.g. "2nd week"), 5$: day of the week (e.g. "Thursday"); (e.g. "$10 up front, then $20 every 2nd week on Wednesday") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:122 +msgid "%1$s %2$s then %3$s every %4$s on %5$s" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount; (e.g. "$10 up front then $30 on the last day of each month") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:135 +msgid "%1$s %2$s then %3$s on the last day of each month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up front then $40 on the 23rd of each month") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:138 +msgid "%1$s %2$s then %3$s on the %4$s of each month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: interval (e.g. "3rd") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:154 +msgid "%1$s %2$s then %3$s on the last day of every %4$s month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g. "3rd") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:157 +msgid "%1$s %2$s then %3$s on the %4$s day of every %5$s month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month (e.g. "23rd") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:175 +msgid "%1$s %2$s then %3$s on %4$s %5$s each year" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g. "23rd"), 6$: interval (e.g. "3rd") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:184 +msgid "%1$s %2$s then %3$s on %4$s %5$s every %6$s year" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: subscription period (e.g. "month" or "3 months") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:194 +msgid "%1$s %2$s then %3$s / %4$s" +msgid_plural "%1$s %2$s then %3$s every %4$s" +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: trial length (e.g. "3 weeks") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:216 +msgid "%1$s after %2$s free trial" +msgstr "" + +#. translators: 1$: trial length (e.g. "3 weeks"), 2$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:219 +msgid "%1$s free trial then %2$s" +msgstr "" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:243 +msgid "in %s" +msgstr "" + +#. translators: placeholder is a localized date and time (e.g. "February 1, 2018 10:20 PM") +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:251 +msgctxt "wcs_get_human_time_diff" +msgid "%s" +msgstr "" + +#. translators: placeholder is a number, this is for the teens +#. translators: placeholder is a number, numbers ending in 4-9, 0 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:296 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:313 +msgid "%sth" +msgstr "" + +#. translators: placeholder is a number, numbers ending in 1 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:301 +msgid "%sst" +msgstr "" + +#. translators: placeholder is a number, numbers ending in 2 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:305 +msgid "%snd" +msgstr "" + +#. translators: placeholder is a number, numbers ending in 3 +#: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:309 +msgid "%srd" +msgstr "" + +#. translators: date placeholder for input, javascript format +#: vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php:40 +msgid "YYYY-MM-DD" +msgstr "" + +#. translators: hour placeholder for time input, javascript format +#: vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php:45 +msgid "HH" +msgstr "" + +#. translators: minute placeholder for time input, javascript format +#: vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php:48 +msgid "MM" +msgstr "" + +#. translators: 1) passed sort order type argument, 2) 'ascending', 3) 'descending'. +#: vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php:266 +msgid "Invalid sort order type: %1$s. The $sort_order argument must be %2$s or %3$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:148 +msgctxt "In wcs_copy_order_meta error message. Refers to origin and target order objects." +msgid "Invalid data. Orders expected aren't orders." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:152 +msgctxt "Refers to the type of the copy being performed: \"copy_order\", \"subscription\", \"renewal_order\", \"resubscribe_order\"" +msgid "Invalid data. Type of copy is not a string." +msgstr "" + +#. translators: placeholders are strftime() strings. +#. translators: Order date parsed by strftime +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:296 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:158 +msgctxt "Used in subscription post title. \"Subscription renewal order - \"" +msgid "%b %d, %Y @ %I:%M %p" +msgstr "" + +#. translators: placeholder is a date. +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:301 +msgid "Subscription Renewal Order – %s" +msgstr "" + +#. translators: placeholder is a date. +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:305 +msgid "Resubscribe Order – %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:324 +msgid "$type passed to the function was not a string." +msgstr "" + +#. translators: placeholder is an order type. +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:329 +msgid "\"%s\" is not a valid new order type." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:519 +msgid "Invalid data. No valid subscription / order was passed in." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:523 +msgid "Invalid data. No valid item id was passed in." +msgstr "" + +#. translators: placeholder is number of days. (e.g. "Bill this every day / 4 days") +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:31 +msgctxt "Subscription billing period." +msgid "day" +msgid_plural "%s days" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 weeks") +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:33 +msgctxt "Subscription billing period." +msgid "week" +msgid_plural "%s weeks" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is number of months. (e.g. "Bill this every month / 4 months") +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:35 +msgctxt "Subscription billing period." +msgid "month" +msgid_plural "%s months" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is number of years. (e.g. "Bill this every year / 4 years") +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:37 +msgctxt "Subscription billing period." +msgid "year" +msgid_plural "%s years" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:88 +msgctxt "Subscription length" +msgid "Never expire" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:93 +msgctxt "Subscription lengths. e.g. \"For 1 day...\"" +msgid "1 day" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:97 +msgctxt "Subscription lengths. e.g. \"For 1 week...\"" +msgid "1 week" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:101 +msgctxt "Subscription lengths. e.g. \"For 1 month...\"" +msgid "1 month" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:105 +msgctxt "Subscription lengths. e.g. \"For 1 year...\"" +msgid "1 year" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:159 +msgctxt "period interval (eg \"$10 _every_ 2 weeks\")" +msgid "every" +msgstr "" + +#. translators: period interval, placeholder is ordinal (eg "$10 every _2nd/3rd/4th_", etc) +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:163 +msgctxt "period interval with ordinal number (e.g. \"every 2nd\"" +msgid "every %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:188 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:189 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "week" +msgid_plural "weeks" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:190 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "month" +msgid_plural "months" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:191 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:210 +msgctxt "no trial period" +msgid "no" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:318 +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/subscription.php:30 +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php:28 +msgid "Resubscribe" +msgstr "" + +#. translators: placeholder is a currency symbol / code +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:20 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:30 +msgid "Subscription Price (%s)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:46 +msgid "Subscription Periods" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:59 +msgctxt "Edit product screen, between the Billing Period and Subscription Length dropdowns" +msgid "for" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:69 +msgid "Subscription Length" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:85 +msgid "Sign-up Fee (%s)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:97 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:104 +msgid "Free Trial" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:105 +msgctxt "example number of days / weeks / months" +msgid "e.g. 3" +msgstr "" + +#. translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks") +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php:118 +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:27 +msgctxt "Trial period dropdown's description in pricing fields" +msgid "An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-synchronisation.php:30 +msgid "Synchronise Renewals" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php:8 +msgid "Label" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php:13 +msgid "Shipping Method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php:34 +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php:36 +msgid "Other" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-tax-html.php:17 +msgid "Recurring Sales Tax:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-tax-html.php:21 +msgid "Shipping Tax:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/html-failed-scheduled-action-notice.php:21 +msgid "An error has occurred while processing a recent subscription related event. For steps on how to fix the affected subscription and to learn more about the possible causes of this error, please read our guide %1$shere%2$s." +msgid_plural "An error has occurred while processing recent subscription related events. For steps on how to fix the affected subscriptions and to learn more about the possible causes of this error, please read our guide %1$shere%2$s." +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/html-failed-scheduled-action-notice.php:31 +msgid "Affected event:" +msgid_plural "Affected events:" +msgstr[0] "" +msgstr[1] "" + +#. translators: $1 the log file name $2 and $3 are opening and closing link tags, respectively. +#: vendor/woocommerce/subscriptions-core/templates/admin/html-failed-scheduled-action-notice.php:38 +msgid "To see further details about these errors, view the %1$s log file from the %2$sWooCommerce logs screen.%2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:31 +msgid "Subscription trial period:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:49 +msgid "Billing interval:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:56 +msgid "Billing Period:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:67 +msgctxt "Subscription Length dropdown's description in pricing fields" +msgid "Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php:32 +msgid "Shipping costs will be calculated once you have provided your address." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php:34 +msgid "There are no shipping methods available. Please double check your address, or contact us if you need any help." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:20 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:36 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals-table.php:21 +msgctxt "table headings in notification email" +msgid "Product" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:21 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:37 +msgctxt "table headings in notification email" +msgid "Quantity" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:22 +msgctxt "table headings in notification email" +msgid "Totals" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:47 +msgctxt "text on button on checkout page" +msgid "Change payment method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:49 +msgctxt "text on button on checkout page" +msgid "Add payment method" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:83 +msgid "Sorry, it seems no payment gateways support changing the recurring payment method. Please contact us if you require assistance or to make alternate arrangements." +msgstr "" + +#. translators: $1: opening tag, $2: closing tag +#: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:92 +msgid "Update the payment method used for %1$sall%2$s of my current subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/recurring-subscription-totals.php:18 +#: vendor/woocommerce/subscriptions-core/templates/checkout/recurring-subscription-totals.php:19 +msgid "Recurring total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/recurring-subtotals.php:18 +#: vendor/woocommerce/subscriptions-core/templates/checkout/recurring-subtotals.php:19 +msgid "Subtotal" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/checkout/recurring-totals.php:17 +msgid "Recurring totals" +msgstr "" + +#. translators: placeholder is the subscription order number wrapped in tags +#: vendor/woocommerce/subscriptions-core/templates/checkout/subscription-receipt.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/email-order-details.php:19 +msgid "Subscription Number: %s" +msgstr "" + +#. translators: placeholder is the subscription's next payment date (either human readable or normal date) wrapped in tags +#: vendor/woocommerce/subscriptions-core/templates/checkout/subscription-receipt.php:24 +msgid "Next Payment Date: %s" +msgstr "" + +#. translators: placeholder is the formatted total to be paid for the subscription wrapped in tags +#: vendor/woocommerce/subscriptions-core/templates/checkout/subscription-receipt.php:30 +msgid "Total: %s" +msgstr "" + +#. translators: placeholder is the display name of the payment method +#: vendor/woocommerce/subscriptions-core/templates/checkout/subscription-receipt.php:37 +msgid "Payment Method: %s" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-renewal-order.php:16 +msgctxt "Used in admin email: new renewal order" +msgid "You have received a subscription renewal order from %1$s. Their order is as follows:" +msgstr "" + +#. translators: $1: customer's first name and last name, $2: how many subscriptions customer switched +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-switch-order.php:18 +msgctxt "Used in switch notification admin email" +msgid "Customer %1$s has switched their subscription. The details of their new subscription are as follows:" +msgid_plural "Customer %1$s has switched %2$d of their subscriptions. The details of their new subscriptions are as follows:" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:20 +msgid "Switch Order Details" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:28 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:26 +msgid "New subscription details" +msgstr "" + +#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-payment-retry.php:23 +msgctxt "In customer renewal invoice email" +msgid "The automatic recurring payment for order #%d from %s has failed. The payment will be retried %3$s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-payment-retry.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-payment-retry.php:21 +msgid "The renewal order is as follows:" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php:16 +msgid "A subscription belonging to %1$s has been cancelled. Their subscription's details are as follows:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:38 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:22 +msgctxt "table headings in notification email" +msgid "Price" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:24 +msgctxt "table headings in notification email" +msgid "End of Prepaid Term" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:41 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:41 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:41 +msgid "-" +msgstr "" + +#. translators: %s: Customer first name +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php:17 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:17 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php:17 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-processing-renewal-order.php:17 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-renewal-order.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-on-hold-renewal-order.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-payment-retry.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-processing-renewal-order.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php:16 +msgid "Hi %s," +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-renewal-order.php:17 +msgid "We have finished processing your subscription renewal order." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php:17 +msgid "You have successfully changed your subscription items. Your new order and subscription details are shown below for your reference:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-on-hold-renewal-order.php:17 +msgid "Thanks for your renewal order. It’s on-hold until we confirm that payment has been received. In the meantime, here’s a reminder of your order:" +msgstr "" + +#. translators: %s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-payment-retry.php:18 +msgctxt "In customer renewal invoice email" +msgid "The automatic payment to renew your subscription has failed. We will retry the payment %s." +msgstr "" + +#. translators: %1$s %2$s: link markup to checkout payment url, note: no full stop due to url at the end +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:21 +msgctxt "In customer renewal invoice email" +msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$sPay Now »%2$s" +msgstr "" + +#. translators: %s: Order number +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-processing-renewal-order.php:19 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-processing-renewal-order.php:18 +msgid "Just to let you know — we've received your subscription renewal order #%s, and it is now being processed:" +msgstr "" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php:20 +msgctxt "In customer renewal invoice email" +msgid "An order has been created for you to renew your subscription on %1$s. To pay for this invoice please use the following link: %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:33 +msgid "Pay Now »" +msgstr "" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:31 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php:23 +msgctxt "In customer renewal invoice email" +msgid "The automatic payment to renew your subscription with %1$s has failed. To reactivate the subscription, please log in and pay for the renewal from your account page: %2$s" +msgstr "" + +#. translators: $1-$2: opening and closing tags $3: order's order number $4: date of order in tags $2: subscription's order number +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:27 +msgctxt "Used in email notification" +msgid "Subscription %1$s#%2$s%3$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:61 +msgid "Note:" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php:16 +msgid "A subscription belonging to %1$s has expired. Their subscription's details are as follows:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:24 +msgctxt "table headings in notification email" +msgid "End Date" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php:16 +msgid "A subscription belonging to %1$s has been suspended by the user. Their subscription's details are as follows:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:24 +msgctxt "table headings in notification email" +msgid "Date Suspended" +msgstr "" + +#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-payment-retry.php:20 +msgctxt "In customer renewal invoice email" +msgid "The automatic recurring payment for order #%1$s from %2$s has failed. The payment will be retried %3$s." +msgstr "" + +#. translators: placeholder is last time subscription was paid +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php:32 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php:32 +msgid "Last Order Date: %s" +msgstr "" + +#. translators: placeholder is localised date string +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php:39 +msgid "End of Prepaid Term: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php:44 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php:44 +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php:40 +msgctxt "in plain emails for subscription information" +msgid "View Subscription: %s" +msgstr "" + +#. translators: placeholder is order's view url +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php:24 +msgid "View your order: %s" +msgstr "" + +#. translators: placeholder is subscription's view url +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php:35 +msgid "View your subscription: %s" +msgstr "" + +#. translators: %1$s: link to checkout payment url, note: no full stop due to url at the end +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-payment-retry.php:21 +msgctxt "In customer renewal invoice email" +msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/email-order-details.php:16 +msgid "Order number: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/email-order-details.php:17 +msgid "Order date: %s" +msgstr "" + +#. translators: placeholder is localised date string +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php:39 +msgid "End Date: %s" +msgstr "" + +#. translators: placeholder is last time subscription was paid +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php:32 +msgid "Last Order: %s" +msgstr "" + +#. translators: placeholder is localised date string +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php:36 +msgid "Date Suspended: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:20 +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:21 +msgid "Subscription information" +msgstr "" + +#. translators: placeholder is subscription's number +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:25 +msgctxt "in plain emails for subscription information" +msgid "Subscription: %s" +msgstr "" + +#. translators: placeholder is either view or edit url for the subscription +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:27 +msgctxt "in plain emails for subscription information" +msgid "View subscription: %s" +msgstr "" + +#. translators: placeholder is localised start date +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:29 +msgctxt "in plain emails for subscription information" +msgid "Start date: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:31 +msgctxt "Used as end date for an indefinite subscription" +msgid "When Cancelled" +msgstr "" + +#. translators: placeholder is localised end date, or "when cancelled" +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:33 +msgctxt "in plain emails for subscription information" +msgid "End date: %s" +msgstr "" + +#. translators: placeholder is the formatted order total for the subscription +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:35 +msgctxt "in plain emails for subscription information" +msgid "Recurring price: %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:38 +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:42 +msgid "Next payment: %s" +msgstr "" + +#. Translators: Placeholder is the My Account URL. +#: vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php:52 +msgid "This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your my account page. %s" +msgid_plural "These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your my account page. %s" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:25 +msgctxt "subscription ID table heading" +msgid "ID" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:26 +msgctxt "table heading" +msgid "Start date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:27 +msgctxt "table heading" +msgid "End date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:28 +msgctxt "table heading" +msgid "Recurring total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:35 +msgctxt "subscription number in email table. (eg: #106)" +msgid "#%s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:37 +msgctxt "Used as end date for an indefinite subscription" +msgid "When cancelled" +msgstr "" + +#. Translators: Placeholders are opening and closing My Account link tags. +#: vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php:58 +msgid "This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your %smy account page%s." +msgid_plural "These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your %smy account page%s." +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:23 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:23 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:39 +msgctxt "table heading" +msgid "Next payment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:33 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:31 +msgid "ID" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:46 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:53 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:42 +msgctxt "Used in data attribute. Escaped" +msgid "Total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:50 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:84 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:46 +msgctxt "view a subscription" +msgid "View" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:61 +msgid "Previous" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:65 +msgid "Next" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:72 +msgid "You have reached the end of subscriptions. Go to the %sfirst page%s." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:74 +msgid "You have no active subscriptions." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:77 +msgid "Browse products" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:15 +msgid "Related orders" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:22 +msgid "Order" +msgstr "" + +#. translators: $1: formatted order total for the order, $2: number of items bought +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:56 +msgid "%1$s for %2$d item" +msgid_plural "%1$s for %2$d items" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:65 +msgctxt "pay for a subscription" +msgid "Pay" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:15 +msgid "Related subscriptions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:24 +msgctxt "customer subscription table header" +msgid "Start date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:25 +msgctxt "customer subscription table header" +msgid "Last order date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:26 +msgctxt "customer subscription table header" +msgid "Next payment date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:27 +msgctxt "customer subscription table header" +msgid "End date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:28 +msgctxt "customer subscription table header" +msgid "Trial end date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:42 +msgid "Auto renew" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:50 +msgid "Enable auto renew" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:57 +msgid "Disable auto renew" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:62 +msgid "Using the auto-renewal toggle is disabled while in staging mode." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:71 +msgid "Payment" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:81 +msgid "Actions" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:94 +msgid "Subscription updates" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php:100 +msgctxt "date on subscription updates list. Will be localized" +msgid "l jS \\o\\f F Y, h:ia" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals-table.php:35 +msgid "Are you sure you want remove this item from your subscription?" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals.php:23 +msgid "Subscription totals" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/subscription.php:32 +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php:30 +msgid "You have an active subscription to this product already." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php:23 +msgid "This product is currently out of stock and unavailable." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php:34 +msgid "You have added a variation of this product to the cart already." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php:45 +msgid "Clear" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:127 +msgctxt "Error message while creating a subscription" +msgid "Invalid created date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:129 +msgctxt "Error message while creating a subscription" +msgid "Subscription created date must be before current day." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:134 +msgctxt "Error message while creating a subscription" +msgid "Invalid date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:139 +msgctxt "Error message while creating a subscription" +msgid "Invalid subscription customer_id." +msgstr "" + +#. translators: placeholder is order date parsed by strftime +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:160 +msgctxt "The post title for the new subscription" +msgid "Subscription – %s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:231 +msgctxt "Subscription status" +msgid "On hold" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:235 +msgctxt "Subscription status" +msgid "Pending Cancellation" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:251 +msgid "Can not get status name. Status is not a string." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:274 +msgid "Can not get address type display name. Address type is not a string." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:340 +msgid "Date type is not a string." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:342 +msgid "Date type can not be an empty string." +msgstr "" + +#. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, leads to plugins.php in admin +#: woocommerce-subscriptions.php:138 +msgid "%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce plugin%4$s must be active for WooCommerce Subscriptions to work. Please %5$sinstall & activate WooCommerce »%6$s" +msgstr "" + +#. translators: 1$-2$: opening and closing tags, 3$: minimum supported WooCommerce version, 4$-5$: opening and closing link tags, leads to plugin admin +#: woocommerce-subscriptions.php:141 +msgid "%1$sWooCommerce Subscriptions is inactive.%2$s This version of Subscriptions requires WooCommerce %3$s or newer. Please %4$supdate WooCommerce to version %3$s or newer »%5$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "week" +msgid_plural "weeks" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "month" +msgid_plural "months" +msgstr[0] "" +msgstr[1] "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#. translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/", %3$d is the length, %4$s is week, month, year +#: vendor/woocommerce/subscriptions-core/build/index.js:6 +msgid "%1$s %2$s %3$d %4$s" +msgstr "" + +#. translators: %s selected shipping rate (ex: flat rate) +#: vendor/woocommerce/subscriptions-core/build/index.js:7 +msgid "via %s" +msgstr "" + +#. Translators: %1$s is a date. +#: vendor/woocommerce/subscriptions-core/build/index.js:9 +msgid "Due: %1$s" +msgstr "" + +#. Translators: %1$s is a date. +#: vendor/woocommerce/subscriptions-core/build/index.js:11 +msgid "Starting: %1$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:11 +msgid "Daily recurring total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:11 +msgid "Weekly recurring total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:11 +msgid "Monthly recurring total" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:11 +msgid "Yearly recurring total" +msgstr "" + +#. translators: %1$s is week, month, year +#: vendor/woocommerce/subscriptions-core/build/index.js:13 +msgid "Recurring total every 2nd %1$s" +msgstr "" + +#. Translators: %1$s is week, month, year +#: vendor/woocommerce/subscriptions-core/build/index.js:15 +msgid "Recurring total every 3rd %1$s" +msgstr "" + +#. Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year +#: vendor/woocommerce/subscriptions-core/build/index.js:17 +msgid "Recurring total every %1$dth %2$s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:17 +msgid "Details" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:17 +msgid "Total due today" +msgstr "" + +#. translators: the word used to describe billing frequency, e.g. "fo1" 1 day or "for" 1 month. +#: vendor/woocommerce/subscriptions-core/build/index.js:18 +msgid "for 1" +msgstr "" + +#. translators: the word used to describe billing frequency, e.g. "for" 6 days or "for" 2 weeks. +#: vendor/woocommerce/subscriptions-core/build/index.js:19 +msgid "for" +msgstr "" + +#. translators: the word used to describe billing frequency, e.g. "every" 6 days or "every" 2 weeks. +#: vendor/woocommerce/subscriptions-core/build/index.js:20 +msgid "every" +msgstr "" + +#. translators: %s Product name. +#: vendor/woocommerce/subscriptions-core/build/index.js:21 +msgid "%s (resubscription)" +msgstr "" + +#. translators: %1$s Product name, %2$s Switch type (upgraded, downgraded, or crossgraded). +#: vendor/woocommerce/subscriptions-core/build/index.js:22 +msgid "%1$s (%2$s)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:22 +msgid "Upgrade" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:22 +msgid "Downgrade" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/build/index.js:22 +msgid "Crossgrade" +msgstr "" + +#. translators: %s is the subscription price to pay immediately (ie: $10). +#: vendor/woocommerce/subscriptions-core/build/index.js:24 +msgid "Due today %s" +msgstr "" + +#. translators: %s is the subscription price to pay immediately (ie: $10). +#: vendor/woocommerce/subscriptions-core/build/index.js:26 +msgid "%s due today" +msgstr "" diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index 6b1b521..0000000 --- a/phpcs.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - WooCommerce Subscriptions dev PHP_CodeSniffer ruleset. - - - - - - - - - - - - - - - - - - - - - - - - - - . - - */node_modules/* - */includes/libraries/* - ./tests/* - ./tmp/* - ./templates/* - ./woo-includes/* - diff --git a/readme.txt b/readme.txt deleted file mode 100644 index d763d26..0000000 --- a/readme.txt +++ /dev/null @@ -1,11 +0,0 @@ -=== WooCommerce Subscriptions === -Contributors: prospress, jconroy, mattallan, thenbrent -Tags: woocommerce, subscriptions, ecommerce, e-commerce, commerce, wordpress ecommerce -Requires at least: 4.0 -Tested up to: 4.8 -Requires PHP: 5.6 -License: GPLv3 -License URI: http://www.gnu.org/licenses/gpl-3.0.html -WC requires at least: 2.5 -WC tested up to: 3.2 -Woo: 27147:6115e6d7e297b623a169fdcf5728b224 diff --git a/templates/checkout/recurring-totals.php b/templates/checkout/recurring-totals.php deleted file mode 100644 index 5a7b756..0000000 --- a/templates/checkout/recurring-totals.php +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - $recurring_cart ) : ?> - next_payment_date ) : ?> - - - - - - - - - - - - - - cart->get_coupons() as $code => $coupon ) : ?> - $recurring_cart ) : ?> - next_payment_date ) : ?> - - - get_coupons() as $recurring_code => $recurring_coupon ) : ?> - - - - - - - - - - - - - - - - - cart->needs_shipping() && WC()->cart->show_shipping() ) : ?> - - - $recurring_cart ) : ?> - next_payment_date ) : ?> - - - get_fees() as $recurring_fee ) : ?> - - name ); ?> - - - - - - cart->tax_display_cart ) : WC()->cart->display_prices_including_tax(); ?> - - - - cart->get_taxes() as $tax_id => $tax_total ) : ?> - $recurring_cart ) : ?> - next_payment_date ) : ?> - - - get_tax_totals() as $recurring_code => $recurring_tax ) : ?> - tax_rate_id ) || $recurring_tax->tax_rate_id !== $tax_id ) { - continue; - } - ?> - - - label ); ?> - formatted_amount, $recurring_cart ) ); ?> - - - formatted_amount, $recurring_cart ) ); ?> - - - - - - - - - - $recurring_cart ) : ?> - next_payment_date ) : ?> - - - - - countries->tax_or_vat() ); ?> - get_taxes_total(), $recurring_cart ) ); ?> - - - get_taxes_total(), $recurring_cart ) ); ?> - - - - - - - - $recurring_cart ) : ?> - next_payment_date ) : ?> - - - - - - - - - - - diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000..903bd0d --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var ?string */ + private $vendorDir; + + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ + private $missingClasses = array(); + + /** @var ?string */ + private $apcuPrefix; + + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + /** + * @return string[] + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array[] + * @psalm-return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return string[] Array of classname => path + * @psalm-return array + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..d50e0c9 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,350 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/includes/libraries/action-scheduler/lib/cron-expression/LICENSE b/vendor/composer/LICENSE old mode 100755 new mode 100644 similarity index 81% rename from includes/libraries/action-scheduler/lib/cron-expression/LICENSE rename to vendor/composer/LICENSE index c6d88ac..f27399a --- a/includes/libraries/action-scheduler/lib/cron-expression/LICENSE +++ b/vendor/composer/LICENSE @@ -1,14 +1,15 @@ -Copyright (c) 2011 Michael Dowling and contributors + +Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -17,3 +18,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..db9b014 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,112 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Composer\\Installers\\AglInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AglInstaller.php', + 'Composer\\Installers\\AimeosInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AimeosInstaller.php', + 'Composer\\Installers\\AnnotateCmsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php', + 'Composer\\Installers\\AsgardInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AsgardInstaller.php', + 'Composer\\Installers\\AttogramInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AttogramInstaller.php', + 'Composer\\Installers\\BaseInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/BaseInstaller.php', + 'Composer\\Installers\\BitrixInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/BitrixInstaller.php', + 'Composer\\Installers\\BonefishInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/BonefishInstaller.php', + 'Composer\\Installers\\CakePHPInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CakePHPInstaller.php', + 'Composer\\Installers\\ChefInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ChefInstaller.php', + 'Composer\\Installers\\CiviCrmInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CiviCrmInstaller.php', + 'Composer\\Installers\\ClanCatsFrameworkInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php', + 'Composer\\Installers\\CockpitInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CockpitInstaller.php', + 'Composer\\Installers\\CodeIgniterInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php', + 'Composer\\Installers\\Concrete5Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Concrete5Installer.php', + 'Composer\\Installers\\CraftInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CraftInstaller.php', + 'Composer\\Installers\\CroogoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CroogoInstaller.php', + 'Composer\\Installers\\DecibelInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DecibelInstaller.php', + 'Composer\\Installers\\DframeInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DframeInstaller.php', + 'Composer\\Installers\\DokuWikiInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DokuWikiInstaller.php', + 'Composer\\Installers\\DolibarrInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DolibarrInstaller.php', + 'Composer\\Installers\\DrupalInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DrupalInstaller.php', + 'Composer\\Installers\\ElggInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ElggInstaller.php', + 'Composer\\Installers\\EliasisInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/EliasisInstaller.php', + 'Composer\\Installers\\ExpressionEngineInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php', + 'Composer\\Installers\\EzPlatformInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/EzPlatformInstaller.php', + 'Composer\\Installers\\FuelInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/FuelInstaller.php', + 'Composer\\Installers\\FuelphpInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/FuelphpInstaller.php', + 'Composer\\Installers\\GravInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/GravInstaller.php', + 'Composer\\Installers\\HuradInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/HuradInstaller.php', + 'Composer\\Installers\\ImageCMSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ImageCMSInstaller.php', + 'Composer\\Installers\\Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Installer.php', + 'Composer\\Installers\\ItopInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ItopInstaller.php', + 'Composer\\Installers\\JoomlaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/JoomlaInstaller.php', + 'Composer\\Installers\\KanboardInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KanboardInstaller.php', + 'Composer\\Installers\\KirbyInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KirbyInstaller.php', + 'Composer\\Installers\\KnownInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KnownInstaller.php', + 'Composer\\Installers\\KodiCMSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KodiCMSInstaller.php', + 'Composer\\Installers\\KohanaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KohanaInstaller.php', + 'Composer\\Installers\\LanManagementSystemInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php', + 'Composer\\Installers\\LaravelInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LaravelInstaller.php', + 'Composer\\Installers\\LavaLiteInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LavaLiteInstaller.php', + 'Composer\\Installers\\LithiumInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LithiumInstaller.php', + 'Composer\\Installers\\MODULEWorkInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php', + 'Composer\\Installers\\MODXEvoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MODXEvoInstaller.php', + 'Composer\\Installers\\MagentoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MagentoInstaller.php', + 'Composer\\Installers\\MajimaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MajimaInstaller.php', + 'Composer\\Installers\\MakoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MakoInstaller.php', + 'Composer\\Installers\\MantisBTInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MantisBTInstaller.php', + 'Composer\\Installers\\MauticInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MauticInstaller.php', + 'Composer\\Installers\\MayaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MayaInstaller.php', + 'Composer\\Installers\\MediaWikiInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MediaWikiInstaller.php', + 'Composer\\Installers\\MiaoxingInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MiaoxingInstaller.php', + 'Composer\\Installers\\MicroweberInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MicroweberInstaller.php', + 'Composer\\Installers\\ModxInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ModxInstaller.php', + 'Composer\\Installers\\MoodleInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MoodleInstaller.php', + 'Composer\\Installers\\OctoberInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OctoberInstaller.php', + 'Composer\\Installers\\OntoWikiInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OntoWikiInstaller.php', + 'Composer\\Installers\\OsclassInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OsclassInstaller.php', + 'Composer\\Installers\\OxidInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OxidInstaller.php', + 'Composer\\Installers\\PPIInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PPIInstaller.php', + 'Composer\\Installers\\PantheonInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PantheonInstaller.php', + 'Composer\\Installers\\PhiftyInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PhiftyInstaller.php', + 'Composer\\Installers\\PhpBBInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PhpBBInstaller.php', + 'Composer\\Installers\\PimcoreInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PimcoreInstaller.php', + 'Composer\\Installers\\PiwikInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PiwikInstaller.php', + 'Composer\\Installers\\PlentymarketsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php', + 'Composer\\Installers\\Plugin' => $vendorDir . '/composer/installers/src/Composer/Installers/Plugin.php', + 'Composer\\Installers\\PortoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PortoInstaller.php', + 'Composer\\Installers\\PrestashopInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PrestashopInstaller.php', + 'Composer\\Installers\\ProcessWireInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ProcessWireInstaller.php', + 'Composer\\Installers\\PuppetInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PuppetInstaller.php', + 'Composer\\Installers\\PxcmsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PxcmsInstaller.php', + 'Composer\\Installers\\RadPHPInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/RadPHPInstaller.php', + 'Composer\\Installers\\ReIndexInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ReIndexInstaller.php', + 'Composer\\Installers\\Redaxo5Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Redaxo5Installer.php', + 'Composer\\Installers\\RedaxoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/RedaxoInstaller.php', + 'Composer\\Installers\\RoundcubeInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/RoundcubeInstaller.php', + 'Composer\\Installers\\SMFInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SMFInstaller.php', + 'Composer\\Installers\\ShopwareInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ShopwareInstaller.php', + 'Composer\\Installers\\SilverStripeInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SilverStripeInstaller.php', + 'Composer\\Installers\\SiteDirectInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SiteDirectInstaller.php', + 'Composer\\Installers\\StarbugInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/StarbugInstaller.php', + 'Composer\\Installers\\SyDESInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SyDESInstaller.php', + 'Composer\\Installers\\SyliusInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SyliusInstaller.php', + 'Composer\\Installers\\Symfony1Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Symfony1Installer.php', + 'Composer\\Installers\\TYPO3CmsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php', + 'Composer\\Installers\\TYPO3FlowInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php', + 'Composer\\Installers\\TaoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TaoInstaller.php', + 'Composer\\Installers\\TastyIgniterInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php', + 'Composer\\Installers\\TheliaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TheliaInstaller.php', + 'Composer\\Installers\\TuskInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TuskInstaller.php', + 'Composer\\Installers\\UserFrostingInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/UserFrostingInstaller.php', + 'Composer\\Installers\\VanillaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/VanillaInstaller.php', + 'Composer\\Installers\\VgmcpInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/VgmcpInstaller.php', + 'Composer\\Installers\\WHMCSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WHMCSInstaller.php', + 'Composer\\Installers\\WinterInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WinterInstaller.php', + 'Composer\\Installers\\WolfCMSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WolfCMSInstaller.php', + 'Composer\\Installers\\WordPressInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WordPressInstaller.php', + 'Composer\\Installers\\YawikInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/YawikInstaller.php', + 'Composer\\Installers\\ZendInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ZendInstaller.php', + 'Composer\\Installers\\ZikulaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ZikulaInstaller.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..b7fc012 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/composer/installers/src/Composer/Installers'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..f1b01a0 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,57 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit253f1c7df0eb4d6d594d9e32faa57a6a::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..a97ea2e --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,138 @@ + + array ( + 'Composer\\Installers\\' => 20, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Composer\\Installers\\' => + array ( + 0 => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Composer\\Installers\\AglInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AglInstaller.php', + 'Composer\\Installers\\AimeosInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AimeosInstaller.php', + 'Composer\\Installers\\AnnotateCmsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php', + 'Composer\\Installers\\AsgardInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AsgardInstaller.php', + 'Composer\\Installers\\AttogramInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AttogramInstaller.php', + 'Composer\\Installers\\BaseInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/BaseInstaller.php', + 'Composer\\Installers\\BitrixInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/BitrixInstaller.php', + 'Composer\\Installers\\BonefishInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/BonefishInstaller.php', + 'Composer\\Installers\\CakePHPInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CakePHPInstaller.php', + 'Composer\\Installers\\ChefInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ChefInstaller.php', + 'Composer\\Installers\\CiviCrmInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CiviCrmInstaller.php', + 'Composer\\Installers\\ClanCatsFrameworkInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php', + 'Composer\\Installers\\CockpitInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CockpitInstaller.php', + 'Composer\\Installers\\CodeIgniterInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php', + 'Composer\\Installers\\Concrete5Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Concrete5Installer.php', + 'Composer\\Installers\\CraftInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CraftInstaller.php', + 'Composer\\Installers\\CroogoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CroogoInstaller.php', + 'Composer\\Installers\\DecibelInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DecibelInstaller.php', + 'Composer\\Installers\\DframeInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DframeInstaller.php', + 'Composer\\Installers\\DokuWikiInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DokuWikiInstaller.php', + 'Composer\\Installers\\DolibarrInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DolibarrInstaller.php', + 'Composer\\Installers\\DrupalInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DrupalInstaller.php', + 'Composer\\Installers\\ElggInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ElggInstaller.php', + 'Composer\\Installers\\EliasisInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/EliasisInstaller.php', + 'Composer\\Installers\\ExpressionEngineInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php', + 'Composer\\Installers\\EzPlatformInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/EzPlatformInstaller.php', + 'Composer\\Installers\\FuelInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/FuelInstaller.php', + 'Composer\\Installers\\FuelphpInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/FuelphpInstaller.php', + 'Composer\\Installers\\GravInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/GravInstaller.php', + 'Composer\\Installers\\HuradInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/HuradInstaller.php', + 'Composer\\Installers\\ImageCMSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ImageCMSInstaller.php', + 'Composer\\Installers\\Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Installer.php', + 'Composer\\Installers\\ItopInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ItopInstaller.php', + 'Composer\\Installers\\JoomlaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/JoomlaInstaller.php', + 'Composer\\Installers\\KanboardInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KanboardInstaller.php', + 'Composer\\Installers\\KirbyInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KirbyInstaller.php', + 'Composer\\Installers\\KnownInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KnownInstaller.php', + 'Composer\\Installers\\KodiCMSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KodiCMSInstaller.php', + 'Composer\\Installers\\KohanaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KohanaInstaller.php', + 'Composer\\Installers\\LanManagementSystemInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php', + 'Composer\\Installers\\LaravelInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LaravelInstaller.php', + 'Composer\\Installers\\LavaLiteInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LavaLiteInstaller.php', + 'Composer\\Installers\\LithiumInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LithiumInstaller.php', + 'Composer\\Installers\\MODULEWorkInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php', + 'Composer\\Installers\\MODXEvoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MODXEvoInstaller.php', + 'Composer\\Installers\\MagentoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MagentoInstaller.php', + 'Composer\\Installers\\MajimaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MajimaInstaller.php', + 'Composer\\Installers\\MakoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MakoInstaller.php', + 'Composer\\Installers\\MantisBTInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MantisBTInstaller.php', + 'Composer\\Installers\\MauticInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MauticInstaller.php', + 'Composer\\Installers\\MayaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MayaInstaller.php', + 'Composer\\Installers\\MediaWikiInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MediaWikiInstaller.php', + 'Composer\\Installers\\MiaoxingInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MiaoxingInstaller.php', + 'Composer\\Installers\\MicroweberInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MicroweberInstaller.php', + 'Composer\\Installers\\ModxInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ModxInstaller.php', + 'Composer\\Installers\\MoodleInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MoodleInstaller.php', + 'Composer\\Installers\\OctoberInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OctoberInstaller.php', + 'Composer\\Installers\\OntoWikiInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OntoWikiInstaller.php', + 'Composer\\Installers\\OsclassInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OsclassInstaller.php', + 'Composer\\Installers\\OxidInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OxidInstaller.php', + 'Composer\\Installers\\PPIInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PPIInstaller.php', + 'Composer\\Installers\\PantheonInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PantheonInstaller.php', + 'Composer\\Installers\\PhiftyInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PhiftyInstaller.php', + 'Composer\\Installers\\PhpBBInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PhpBBInstaller.php', + 'Composer\\Installers\\PimcoreInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PimcoreInstaller.php', + 'Composer\\Installers\\PiwikInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PiwikInstaller.php', + 'Composer\\Installers\\PlentymarketsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php', + 'Composer\\Installers\\Plugin' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Plugin.php', + 'Composer\\Installers\\PortoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PortoInstaller.php', + 'Composer\\Installers\\PrestashopInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PrestashopInstaller.php', + 'Composer\\Installers\\ProcessWireInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ProcessWireInstaller.php', + 'Composer\\Installers\\PuppetInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PuppetInstaller.php', + 'Composer\\Installers\\PxcmsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PxcmsInstaller.php', + 'Composer\\Installers\\RadPHPInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/RadPHPInstaller.php', + 'Composer\\Installers\\ReIndexInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ReIndexInstaller.php', + 'Composer\\Installers\\Redaxo5Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Redaxo5Installer.php', + 'Composer\\Installers\\RedaxoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/RedaxoInstaller.php', + 'Composer\\Installers\\RoundcubeInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/RoundcubeInstaller.php', + 'Composer\\Installers\\SMFInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SMFInstaller.php', + 'Composer\\Installers\\ShopwareInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ShopwareInstaller.php', + 'Composer\\Installers\\SilverStripeInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SilverStripeInstaller.php', + 'Composer\\Installers\\SiteDirectInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SiteDirectInstaller.php', + 'Composer\\Installers\\StarbugInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/StarbugInstaller.php', + 'Composer\\Installers\\SyDESInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SyDESInstaller.php', + 'Composer\\Installers\\SyliusInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SyliusInstaller.php', + 'Composer\\Installers\\Symfony1Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Symfony1Installer.php', + 'Composer\\Installers\\TYPO3CmsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php', + 'Composer\\Installers\\TYPO3FlowInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php', + 'Composer\\Installers\\TaoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TaoInstaller.php', + 'Composer\\Installers\\TastyIgniterInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php', + 'Composer\\Installers\\TheliaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TheliaInstaller.php', + 'Composer\\Installers\\TuskInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TuskInstaller.php', + 'Composer\\Installers\\UserFrostingInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/UserFrostingInstaller.php', + 'Composer\\Installers\\VanillaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/VanillaInstaller.php', + 'Composer\\Installers\\VgmcpInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/VgmcpInstaller.php', + 'Composer\\Installers\\WHMCSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WHMCSInstaller.php', + 'Composer\\Installers\\WinterInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WinterInstaller.php', + 'Composer\\Installers\\WolfCMSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WolfCMSInstaller.php', + 'Composer\\Installers\\WordPressInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WordPressInstaller.php', + 'Composer\\Installers\\YawikInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/YawikInstaller.php', + 'Composer\\Installers\\ZendInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ZendInstaller.php', + 'Composer\\Installers\\ZikulaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ZikulaInstaller.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit253f1c7df0eb4d6d594d9e32faa57a6a::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit253f1c7df0eb4d6d594d9e32faa57a6a::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit253f1c7df0eb4d6d594d9e32faa57a6a::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..01d4bd2 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,220 @@ +{ + "packages": [ + { + "name": "composer/installers", + "version": "v1.12.0", + "version_normalized": "1.12.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/installers.git", + "reference": "d20a64ed3c94748397ff5973488761b22f6d3f19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/installers/zipball/d20a64ed3c94748397ff5973488761b22f6d3f19", + "reference": "d20a64ed3c94748397ff5973488761b22f6d3f19", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0" + }, + "replace": { + "roundcube/plugin-installer": "*", + "shama/baton": "*" + }, + "require-dev": { + "composer/composer": "1.6.* || ^2.0", + "composer/semver": "^1 || ^3", + "phpstan/phpstan": "^0.12.55", + "phpstan/phpstan-phpunit": "^0.12.16", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^2.3" + }, + "time": "2021-09-13T08:19:44+00:00", + "type": "composer-plugin", + "extra": { + "class": "Composer\\Installers\\Plugin", + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\Installers\\": "src/Composer/Installers" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" + } + ], + "description": "A multi-framework Composer library installer", + "homepage": "https://composer.github.io/installers/", + "keywords": [ + "Craft", + "Dolibarr", + "Eliasis", + "Hurad", + "ImageCMS", + "Kanboard", + "Lan Management System", + "MODX Evo", + "MantisBT", + "Mautic", + "Maya", + "OXID", + "Plentymarkets", + "Porto", + "RadPHP", + "SMF", + "Starbug", + "Thelia", + "Whmcs", + "WolfCMS", + "agl", + "aimeos", + "annotatecms", + "attogram", + "bitrix", + "cakephp", + "chef", + "cockpit", + "codeigniter", + "concrete5", + "croogo", + "dokuwiki", + "drupal", + "eZ Platform", + "elgg", + "expressionengine", + "fuelphp", + "grav", + "installer", + "itop", + "joomla", + "known", + "kohana", + "laravel", + "lavalite", + "lithium", + "magento", + "majima", + "mako", + "mediawiki", + "miaoxing", + "modulework", + "modx", + "moodle", + "osclass", + "pantheon", + "phpbb", + "piwik", + "ppi", + "processwire", + "puppet", + "pxcms", + "reindex", + "roundcube", + "shopware", + "silverstripe", + "sydes", + "sylius", + "symfony", + "tastyigniter", + "typo3", + "wordpress", + "yawik", + "zend", + "zikula" + ], + "support": { + "issues": "https://github.com/composer/installers/issues", + "source": "https://github.com/composer/installers/tree/v1.12.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./installers" + }, + { + "name": "woocommerce/subscriptions-core", + "version": "2.3.0", + "version_normalized": "2.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Automattic/woocommerce-subscriptions-core.git", + "reference": "8017438f8e0cfc16494344f783fb134f77284d58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/8017438f8e0cfc16494344f783fb134f77284d58", + "reference": "8017438f8e0cfc16494344f783fb134f77284d58", + "shasum": "" + }, + "require": { + "composer/installers": "~1.2", + "php": "^7.1" + }, + "require-dev": { + "dave-liddament/sarb": "^1.1", + "phpunit/phpunit": "9.5.14", + "woocommerce/woocommerce-sniffs": "0.1.0", + "yoast/phpunit-polyfills": "1.0.3" + }, + "time": "2022-10-07T03:45:34+00:00", + "type": "wordpress-plugin", + "extra": { + "phpcodesniffer-search-depth": 2 + }, + "installation-source": "dist", + "archive": { + "exclude": [ + "!/build", + "*.zip", + "node_modules" + ] + }, + "scripts": { + "phpcs": [ + "bin/phpcs.sh" + ], + "lint": [ + "find . \\( -path ./vendor \\) -prune -o \\( -name '*.php' \\) -exec php -lf {} \\;| (! grep -v \"No syntax errors detected\" )" + ], + "test": [ + "phpunit" + ] + }, + "license": [ + "GPL-3.0-or-later" + ], + "description": "Sell products and services with recurring payments in your WooCommerce Store.", + "homepage": "https://github.com/Automattic/woocommerce-subscriptions-core", + "support": { + "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/2.3.0", + "issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues" + }, + "install-path": "../woocommerce/subscriptions-core" + } + ], + "dev": false, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000..96e5cc5 --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,53 @@ + array( + 'pretty_version' => 'dev-trunk', + 'version' => 'dev-trunk', + 'type' => 'wordpress-plugin', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => '1b8773fe15dd9d70a59bfde2d5593191398b6096', + 'name' => 'woocommerce/woocommerce-subscriptions', + 'dev' => false, + ), + 'versions' => array( + 'composer/installers' => array( + 'pretty_version' => 'v1.12.0', + 'version' => '1.12.0.0', + 'type' => 'composer-plugin', + 'install_path' => __DIR__ . '/./installers', + 'aliases' => array(), + 'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19', + 'dev_requirement' => false, + ), + 'roundcube/plugin-installer' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + 'shama/baton' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + 'woocommerce/subscriptions-core' => array( + 'pretty_version' => '2.3.0', + 'version' => '2.3.0.0', + 'type' => 'wordpress-plugin', + 'install_path' => __DIR__ . '/../woocommerce/subscriptions-core', + 'aliases' => array(), + 'reference' => '8017438f8e0cfc16494344f783fb134f77284d58', + 'dev_requirement' => false, + ), + 'woocommerce/woocommerce-subscriptions' => array( + 'pretty_version' => 'dev-trunk', + 'version' => 'dev-trunk', + 'type' => 'wordpress-plugin', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => '1b8773fe15dd9d70a59bfde2d5593191398b6096', + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/installers/.github/workflows/continuous-integration.yml b/vendor/composer/installers/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..34b8f91 --- /dev/null +++ b/vendor/composer/installers/.github/workflows/continuous-integration.yml @@ -0,0 +1,76 @@ +name: "Continuous Integration" + +on: + - push + - pull_request + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: "1" + +jobs: + tests: + name: "CI" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "5.3" + - "5.4" + - "5.5" + - "5.6" + - "7.0" + - "7.1" + - "7.2" + - "7.3" + - "7.4" + - "8.0" + - "8.1" + dependencies: [locked] + include: + - php-version: "5.3" + dependencies: lowest + - php-version: "8.1" + dependencies: lowest + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + tools: composer:snapshot + + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: "Handle lowest dependencies update" + if: "contains(matrix.dependencies, 'lowest')" + run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" + + - name: "Upgrade phpunit-bridge if needed for php 8 lowest build" + if: "contains(matrix.php-version, '8.')" + run: | + composer require symfony/phpunit-bridge:^5.3.3 --dev --no-update + + - name: "Install latest dependencies" + run: | + # Remove PHPStan as it requires a newer PHP + composer remove phpstan/phpstan phpstan/phpstan-phpunit --dev --no-update + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "Run tests" + run: "vendor/bin/simple-phpunit --verbose" diff --git a/vendor/composer/installers/.github/workflows/lint.yml b/vendor/composer/installers/.github/workflows/lint.yml new file mode 100644 index 0000000..81a1ac4 --- /dev/null +++ b/vendor/composer/installers/.github/workflows/lint.yml @@ -0,0 +1,30 @@ +name: "PHP Lint" + +on: + - push + - pull_request + +jobs: + tests: + name: "Lint" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "5.3" + - "8.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: "Lint PHP files" + run: "find src/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" diff --git a/vendor/composer/installers/.github/workflows/phpstan.yml b/vendor/composer/installers/.github/workflows/phpstan.yml new file mode 100644 index 0000000..ac4c4a9 --- /dev/null +++ b/vendor/composer/installers/.github/workflows/phpstan.yml @@ -0,0 +1,51 @@ +name: "PHPStan" + +on: + - push + - pull_request + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + SYMFONY_PHPUNIT_VERSION: "" + +jobs: + tests: + name: "PHPStan" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + # pinned to 7.4 because we need PHPUnit 7.5 which does not support PHP 8 + - "7.4" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: "Install latest dependencies" + run: "composer update ${{ env.COMPOSER_FLAGS }}" + + - name: Run PHPStan + # Locked to phpunit 7.5 here as newer ones have void return types which break inheritance + run: | + composer require --dev phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }} + vendor/bin/phpstan analyse diff --git a/vendor/composer/installers/LICENSE b/vendor/composer/installers/LICENSE new file mode 100644 index 0000000..85f97fc --- /dev/null +++ b/vendor/composer/installers/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Kyle Robinson Young + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/vendor/composer/installers/composer.json b/vendor/composer/installers/composer.json new file mode 100644 index 0000000..4a7fd3c --- /dev/null +++ b/vendor/composer/installers/composer.json @@ -0,0 +1,122 @@ +{ + "name": "composer/installers", + "type": "composer-plugin", + "license": "MIT", + "description": "A multi-framework Composer library installer", + "keywords": [ + "installer", + "Aimeos", + "AGL", + "AnnotateCms", + "Attogram", + "Bitrix", + "CakePHP", + "Chef", + "Cockpit", + "CodeIgniter", + "concrete5", + "Craft", + "Croogo", + "DokuWiki", + "Dolibarr", + "Drupal", + "Elgg", + "Eliasis", + "ExpressionEngine", + "eZ Platform", + "FuelPHP", + "Grav", + "Hurad", + "ImageCMS", + "iTop", + "Joomla", + "Kanboard", + "Known", + "Kohana", + "Lan Management System", + "Laravel", + "Lavalite", + "Lithium", + "Magento", + "majima", + "Mako", + "MantisBT", + "Mautic", + "Maya", + "MODX", + "MODX Evo", + "MediaWiki", + "Miaoxing", + "OXID", + "osclass", + "MODULEWork", + "Moodle", + "Pantheon", + "Piwik", + "pxcms", + "phpBB", + "Plentymarkets", + "PPI", + "Puppet", + "Porto", + "ProcessWire", + "RadPHP", + "ReIndex", + "Roundcube", + "shopware", + "SilverStripe", + "SMF", + "Starbug", + "SyDES", + "Sylius", + "symfony", + "TastyIgniter", + "Thelia", + "TYPO3", + "WHMCS", + "WolfCMS", + "WordPress", + "YAWIK", + "Zend", + "Zikula" + ], + "homepage": "https://composer.github.io/installers/", + "authors": [ + { + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" + } + ], + "autoload": { + "psr-4": { "Composer\\Installers\\": "src/Composer/Installers" } + }, + "autoload-dev": { + "psr-4": { "Composer\\Installers\\Test\\": "tests/Composer/Installers/Test" } + }, + "extra": { + "class": "Composer\\Installers\\Plugin", + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "replace": { + "shama/baton": "*", + "roundcube/plugin-installer": "*" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "1.6.* || ^2.0", + "composer/semver": "^1 || ^3", + "symfony/phpunit-bridge": "^4.2 || ^5", + "phpstan/phpstan": "^0.12.55", + "symfony/process": "^2.3", + "phpstan/phpstan-phpunit": "^0.12.16" + }, + "scripts": { + "test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit", + "phpstan": "vendor/bin/phpstan analyse" + } +} diff --git a/vendor/composer/installers/phpstan.neon.dist b/vendor/composer/installers/phpstan.neon.dist new file mode 100644 index 0000000..8e3d81e --- /dev/null +++ b/vendor/composer/installers/phpstan.neon.dist @@ -0,0 +1,10 @@ +parameters: + level: 5 + paths: + - src + - tests + excludes_analyse: + - tests/Composer/Installers/Test/PolyfillTestCase.php + +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon diff --git a/vendor/composer/installers/src/Composer/Installers/AglInstaller.php b/vendor/composer/installers/src/Composer/Installers/AglInstaller.php new file mode 100644 index 0000000..01b8a41 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/AglInstaller.php @@ -0,0 +1,21 @@ + 'More/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = preg_replace_callback('/(?:^|_|-)(.?)/', function ($matches) { + return strtoupper($matches[1]); + }, $vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php b/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php new file mode 100644 index 0000000..79a0e95 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php @@ -0,0 +1,9 @@ + 'ext/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php b/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php new file mode 100644 index 0000000..89d7ad9 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php @@ -0,0 +1,11 @@ + 'addons/modules/{$name}/', + 'component' => 'addons/components/{$name}/', + 'service' => 'addons/services/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php b/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php new file mode 100644 index 0000000..22dad1b --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php @@ -0,0 +1,49 @@ + 'Modules/{$name}/', + 'theme' => 'Themes/{$name}/' + ); + + /** + * Format package name. + * + * For package type asgard-module, cut off a trailing '-plugin' if present. + * + * For package type asgard-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'asgard-module') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'asgard-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-module$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php b/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php new file mode 100644 index 0000000..d62fd8f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php b/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php new file mode 100644 index 0000000..70dde90 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php @@ -0,0 +1,137 @@ +composer = $composer; + $this->package = $package; + $this->io = $io; + } + + /** + * Return the install path based on package type. + * + * @param PackageInterface $package + * @param string $frameworkType + * @return string + */ + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + $type = $this->package->getType(); + + $prettyName = $this->package->getPrettyName(); + if (strpos($prettyName, '/') !== false) { + list($vendor, $name) = explode('/', $prettyName); + } else { + $vendor = ''; + $name = $prettyName; + } + + $availableVars = $this->inflectPackageVars(compact('name', 'vendor', 'type')); + + $extra = $package->getExtra(); + if (!empty($extra['installer-name'])) { + $availableVars['name'] = $extra['installer-name']; + } + + if ($this->composer->getPackage()) { + $extra = $this->composer->getPackage()->getExtra(); + if (!empty($extra['installer-paths'])) { + $customPath = $this->mapCustomInstallPaths($extra['installer-paths'], $prettyName, $type, $vendor); + if ($customPath !== false) { + return $this->templatePath($customPath, $availableVars); + } + } + } + + $packageType = substr($type, strlen($frameworkType) + 1); + $locations = $this->getLocations(); + if (!isset($locations[$packageType])) { + throw new \InvalidArgumentException(sprintf('Package type "%s" is not supported', $type)); + } + + return $this->templatePath($locations[$packageType], $availableVars); + } + + /** + * For an installer to override to modify the vars per installer. + * + * @param array $vars This will normally receive array{name: string, vendor: string, type: string} + * @return array + */ + public function inflectPackageVars($vars) + { + return $vars; + } + + /** + * Gets the installer's locations + * + * @return array map of package types => install path + */ + public function getLocations() + { + return $this->locations; + } + + /** + * Replace vars in a path + * + * @param string $path + * @param array $vars + * @return string + */ + protected function templatePath($path, array $vars = array()) + { + if (strpos($path, '{') !== false) { + extract($vars); + preg_match_all('@\{\$([A-Za-z0-9_]*)\}@i', $path, $matches); + if (!empty($matches[1])) { + foreach ($matches[1] as $var) { + $path = str_replace('{$' . $var . '}', $$var, $path); + } + } + } + + return $path; + } + + /** + * Search through a passed paths array for a custom install path. + * + * @param array $paths + * @param string $name + * @param string $type + * @param string $vendor = NULL + * @return string|false + */ + protected function mapCustomInstallPaths(array $paths, $name, $type, $vendor = NULL) + { + foreach ($paths as $path => $names) { + $names = (array) $names; + if (in_array($name, $names) || in_array('type:' . $type, $names) || in_array('vendor:' . $vendor, $names)) { + return $path; + } + } + + return false; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php b/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php new file mode 100644 index 0000000..e80cd1e --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php @@ -0,0 +1,126 @@ +.`. + * - `bitrix-d7-component` — copy the component to directory `bitrix/components//`. + * - `bitrix-d7-template` — copy the template to directory `bitrix/templates/_`. + * + * You can set custom path to directory with Bitrix kernel in `composer.json`: + * + * ```json + * { + * "extra": { + * "bitrix-dir": "s1/bitrix" + * } + * } + * ``` + * + * @author Nik Samokhvalov + * @author Denis Kulichkin + */ +class BitrixInstaller extends BaseInstaller +{ + protected $locations = array( + 'module' => '{$bitrix_dir}/modules/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken) + 'component' => '{$bitrix_dir}/components/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken) + 'theme' => '{$bitrix_dir}/templates/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken) + 'd7-module' => '{$bitrix_dir}/modules/{$vendor}.{$name}/', + 'd7-component' => '{$bitrix_dir}/components/{$vendor}/{$name}/', + 'd7-template' => '{$bitrix_dir}/templates/{$vendor}_{$name}/', + ); + + /** + * @var array Storage for informations about duplicates at all the time of installation packages. + */ + private static $checkedDuplicates = array(); + + /** + * {@inheritdoc} + */ + public function inflectPackageVars($vars) + { + if ($this->composer->getPackage()) { + $extra = $this->composer->getPackage()->getExtra(); + + if (isset($extra['bitrix-dir'])) { + $vars['bitrix_dir'] = $extra['bitrix-dir']; + } + } + + if (!isset($vars['bitrix_dir'])) { + $vars['bitrix_dir'] = 'bitrix'; + } + + return parent::inflectPackageVars($vars); + } + + /** + * {@inheritdoc} + */ + protected function templatePath($path, array $vars = array()) + { + $templatePath = parent::templatePath($path, $vars); + $this->checkDuplicates($templatePath, $vars); + + return $templatePath; + } + + /** + * Duplicates search packages. + * + * @param string $path + * @param array $vars + */ + protected function checkDuplicates($path, array $vars = array()) + { + $packageType = substr($vars['type'], strlen('bitrix') + 1); + $localDir = explode('/', $vars['bitrix_dir']); + array_pop($localDir); + $localDir[] = 'local'; + $localDir = implode('/', $localDir); + + $oldPath = str_replace( + array('{$bitrix_dir}', '{$name}'), + array($localDir, $vars['name']), + $this->locations[$packageType] + ); + + if (in_array($oldPath, static::$checkedDuplicates)) { + return; + } + + if ($oldPath !== $path && file_exists($oldPath) && $this->io && $this->io->isInteractive()) { + + $this->io->writeError(' Duplication of packages:'); + $this->io->writeError(' Package ' . $oldPath . ' will be called instead package ' . $path . ''); + + while (true) { + switch ($this->io->ask(' Delete ' . $oldPath . ' [y,n,?]? ', '?')) { + case 'y': + $fs = new Filesystem(); + $fs->removeDirectory($oldPath); + break 2; + + case 'n': + break 2; + + case '?': + default: + $this->io->writeError(array( + ' y - delete package ' . $oldPath . ' and to continue with the installation', + ' n - don\'t delete and to continue with the installation', + )); + $this->io->writeError(' ? - print help'); + break; + } + } + } + + static::$checkedDuplicates[] = $oldPath; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php b/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php new file mode 100644 index 0000000..da3aad2 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php @@ -0,0 +1,9 @@ + 'Packages/{$vendor}/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php b/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php new file mode 100644 index 0000000..1e2ddd0 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php @@ -0,0 +1,66 @@ + 'Plugin/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + if ($this->matchesCakeVersion('>=', '3.0.0')) { + return $vars; + } + + $nameParts = explode('/', $vars['name']); + foreach ($nameParts as &$value) { + $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value)); + $value = str_replace(array('-', '_'), ' ', $value); + $value = str_replace(' ', '', ucwords($value)); + } + $vars['name'] = implode('/', $nameParts); + + return $vars; + } + + /** + * Change the default plugin location when cakephp >= 3.0 + */ + public function getLocations() + { + if ($this->matchesCakeVersion('>=', '3.0.0')) { + $this->locations['plugin'] = $this->composer->getConfig()->get('vendor-dir') . '/{$vendor}/{$name}/'; + } + return $this->locations; + } + + /** + * Check if CakePHP version matches against a version + * + * @param string $matcher + * @param string $version + * @return bool + * @phpstan-param Constraint::STR_OP_* $matcher + */ + protected function matchesCakeVersion($matcher, $version) + { + $repositoryManager = $this->composer->getRepositoryManager(); + if (! $repositoryManager) { + return false; + } + + $repos = $repositoryManager->getLocalRepository(); + if (!$repos) { + return false; + } + + return $repos->findPackage('cakephp/cakephp', new Constraint($matcher, $version)) !== null; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php b/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php new file mode 100644 index 0000000..ab2f9aa --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php @@ -0,0 +1,11 @@ + 'Chef/{$vendor}/{$name}/', + 'role' => 'Chef/roles/{$name}/', + ); +} + diff --git a/vendor/composer/installers/src/Composer/Installers/CiviCrmInstaller.php b/vendor/composer/installers/src/Composer/Installers/CiviCrmInstaller.php new file mode 100644 index 0000000..6673aea --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/CiviCrmInstaller.php @@ -0,0 +1,9 @@ + 'ext/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php b/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php new file mode 100644 index 0000000..c887815 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php @@ -0,0 +1,10 @@ + 'CCF/orbit/{$name}/', + 'theme' => 'CCF/app/themes/{$name}/', + ); +} \ No newline at end of file diff --git a/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php b/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php new file mode 100644 index 0000000..053f3ff --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php @@ -0,0 +1,32 @@ + 'cockpit/modules/addons/{$name}/', + ); + + /** + * Format module name. + * + * Strip `module-` prefix from package name. + * + * {@inheritDoc} + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] == 'cockpit-module') { + return $this->inflectModuleVars($vars); + } + + return $vars; + } + + public function inflectModuleVars($vars) + { + $vars['name'] = ucfirst(preg_replace('/cockpit-/i', '', $vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php b/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php new file mode 100644 index 0000000..3b4a4ec --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php @@ -0,0 +1,11 @@ + 'application/libraries/{$name}/', + 'third-party' => 'application/third_party/{$name}/', + 'module' => 'application/modules/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php b/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php new file mode 100644 index 0000000..5c01baf --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php @@ -0,0 +1,13 @@ + 'concrete/', + 'block' => 'application/blocks/{$name}/', + 'package' => 'packages/{$name}/', + 'theme' => 'application/themes/{$name}/', + 'update' => 'updates/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php b/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php new file mode 100644 index 0000000..d37a77a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php @@ -0,0 +1,35 @@ + 'craft/plugins/{$name}/', + ); + + /** + * Strip `craft-` prefix and/or `-plugin` suffix from package names + * + * @param array $vars + * + * @return array + */ + final public function inflectPackageVars($vars) + { + return $this->inflectPluginVars($vars); + } + + private function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-' . self::NAME_SUFFIX . '$/i', '', $vars['name']); + $vars['name'] = preg_replace('/^' . self::NAME_PREFIX . '-/i', '', $vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php b/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php new file mode 100644 index 0000000..d94219d --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php @@ -0,0 +1,21 @@ + 'Plugin/{$name}/', + 'theme' => 'View/Themed/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(str_replace(array('-', '_'), ' ', $vars['name'])); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php b/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php new file mode 100644 index 0000000..f4837a6 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php @@ -0,0 +1,10 @@ + 'app/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/DframeInstaller.php b/vendor/composer/installers/src/Composer/Installers/DframeInstaller.php new file mode 100644 index 0000000..7078816 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/DframeInstaller.php @@ -0,0 +1,10 @@ + 'modules/{$vendor}/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php b/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php new file mode 100644 index 0000000..cfd638d --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php @@ -0,0 +1,50 @@ + 'lib/plugins/{$name}/', + 'template' => 'lib/tpl/{$name}/', + ); + + /** + * Format package name. + * + * For package type dokuwiki-plugin, cut off a trailing '-plugin', + * or leading dokuwiki_ if present. + * + * For package type dokuwiki-template, cut off a trailing '-template' if present. + * + */ + public function inflectPackageVars($vars) + { + + if ($vars['type'] === 'dokuwiki-plugin') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'dokuwiki-template') { + return $this->inflectTemplateVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-plugin$/', '', $vars['name']); + $vars['name'] = preg_replace('/^dokuwiki_?-?/', '', $vars['name']); + + return $vars; + } + + protected function inflectTemplateVars($vars) + { + $vars['name'] = preg_replace('/-template$/', '', $vars['name']); + $vars['name'] = preg_replace('/^dokuwiki_?-?/', '', $vars['name']); + + return $vars; + } + +} diff --git a/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php b/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php new file mode 100644 index 0000000..21f7e8e --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php @@ -0,0 +1,16 @@ + + */ +class DolibarrInstaller extends BaseInstaller +{ + //TODO: Add support for scripts and themes + protected $locations = array( + 'module' => 'htdocs/custom/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php b/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php new file mode 100644 index 0000000..7328239 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php @@ -0,0 +1,22 @@ + 'core/', + 'module' => 'modules/{$name}/', + 'theme' => 'themes/{$name}/', + 'library' => 'libraries/{$name}/', + 'profile' => 'profiles/{$name}/', + 'database-driver' => 'drivers/lib/Drupal/Driver/Database/{$name}/', + 'drush' => 'drush/{$name}/', + 'custom-theme' => 'themes/custom/{$name}/', + 'custom-module' => 'modules/custom/{$name}/', + 'custom-profile' => 'profiles/custom/{$name}/', + 'drupal-multisite' => 'sites/{$name}/', + 'console' => 'console/{$name}/', + 'console-language' => 'console/language/{$name}/', + 'config' => 'config/sync/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php b/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php new file mode 100644 index 0000000..c0bb609 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php @@ -0,0 +1,9 @@ + 'mod/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php b/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php new file mode 100644 index 0000000..6f3dc97 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php @@ -0,0 +1,12 @@ + 'components/{$name}/', + 'module' => 'modules/{$name}/', + 'plugin' => 'plugins/{$name}/', + 'template' => 'templates/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php b/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php new file mode 100644 index 0000000..d5321a8 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php @@ -0,0 +1,29 @@ + 'system/expressionengine/third_party/{$name}/', + 'theme' => 'themes/third_party/{$name}/', + ); + + private $ee3Locations = array( + 'addon' => 'system/user/addons/{$name}/', + 'theme' => 'themes/user/{$name}/', + ); + + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + + $version = "{$frameworkType}Locations"; + $this->locations = $this->$version; + + return parent::getInstallPath($package, $frameworkType); + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/EzPlatformInstaller.php b/vendor/composer/installers/src/Composer/Installers/EzPlatformInstaller.php new file mode 100644 index 0000000..f30ebcc --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/EzPlatformInstaller.php @@ -0,0 +1,10 @@ + 'web/assets/ezplatform/', + 'assets' => 'web/assets/ezplatform/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php b/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php new file mode 100644 index 0000000..6eba2e3 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php @@ -0,0 +1,11 @@ + 'fuel/app/modules/{$name}/', + 'package' => 'fuel/packages/{$name}/', + 'theme' => 'fuel/app/themes/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php b/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php new file mode 100644 index 0000000..29d980b --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php @@ -0,0 +1,9 @@ + 'components/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/GravInstaller.php b/vendor/composer/installers/src/Composer/Installers/GravInstaller.php new file mode 100644 index 0000000..dbe63e0 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/GravInstaller.php @@ -0,0 +1,30 @@ + 'user/plugins/{$name}/', + 'theme' => 'user/themes/{$name}/', + ); + + /** + * Format package name + * + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $restrictedWords = implode('|', array_keys($this->locations)); + + $vars['name'] = strtolower($vars['name']); + $vars['name'] = preg_replace('/^(?:grav-)?(?:(?:'.$restrictedWords.')-)?(.*?)(?:-(?:'.$restrictedWords.'))?$/ui', + '$1', + $vars['name'] + ); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php b/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php new file mode 100644 index 0000000..8fe017f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php @@ -0,0 +1,25 @@ + 'plugins/{$name}/', + 'theme' => 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $nameParts = explode('/', $vars['name']); + foreach ($nameParts as &$value) { + $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value)); + $value = str_replace(array('-', '_'), ' ', $value); + $value = str_replace(' ', '', ucwords($value)); + } + $vars['name'] = implode('/', $nameParts); + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php b/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php new file mode 100644 index 0000000..5e2142e --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php @@ -0,0 +1,11 @@ + 'templates/{$name}/', + 'module' => 'application/modules/{$name}/', + 'library' => 'application/libraries/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/Installer.php b/vendor/composer/installers/src/Composer/Installers/Installer.php new file mode 100644 index 0000000..9c9c24f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/Installer.php @@ -0,0 +1,298 @@ + 'AimeosInstaller', + 'asgard' => 'AsgardInstaller', + 'attogram' => 'AttogramInstaller', + 'agl' => 'AglInstaller', + 'annotatecms' => 'AnnotateCmsInstaller', + 'bitrix' => 'BitrixInstaller', + 'bonefish' => 'BonefishInstaller', + 'cakephp' => 'CakePHPInstaller', + 'chef' => 'ChefInstaller', + 'civicrm' => 'CiviCrmInstaller', + 'ccframework' => 'ClanCatsFrameworkInstaller', + 'cockpit' => 'CockpitInstaller', + 'codeigniter' => 'CodeIgniterInstaller', + 'concrete5' => 'Concrete5Installer', + 'craft' => 'CraftInstaller', + 'croogo' => 'CroogoInstaller', + 'dframe' => 'DframeInstaller', + 'dokuwiki' => 'DokuWikiInstaller', + 'dolibarr' => 'DolibarrInstaller', + 'decibel' => 'DecibelInstaller', + 'drupal' => 'DrupalInstaller', + 'elgg' => 'ElggInstaller', + 'eliasis' => 'EliasisInstaller', + 'ee3' => 'ExpressionEngineInstaller', + 'ee2' => 'ExpressionEngineInstaller', + 'ezplatform' => 'EzPlatformInstaller', + 'fuel' => 'FuelInstaller', + 'fuelphp' => 'FuelphpInstaller', + 'grav' => 'GravInstaller', + 'hurad' => 'HuradInstaller', + 'tastyigniter' => 'TastyIgniterInstaller', + 'imagecms' => 'ImageCMSInstaller', + 'itop' => 'ItopInstaller', + 'joomla' => 'JoomlaInstaller', + 'kanboard' => 'KanboardInstaller', + 'kirby' => 'KirbyInstaller', + 'known' => 'KnownInstaller', + 'kodicms' => 'KodiCMSInstaller', + 'kohana' => 'KohanaInstaller', + 'lms' => 'LanManagementSystemInstaller', + 'laravel' => 'LaravelInstaller', + 'lavalite' => 'LavaLiteInstaller', + 'lithium' => 'LithiumInstaller', + 'magento' => 'MagentoInstaller', + 'majima' => 'MajimaInstaller', + 'mantisbt' => 'MantisBTInstaller', + 'mako' => 'MakoInstaller', + 'maya' => 'MayaInstaller', + 'mautic' => 'MauticInstaller', + 'mediawiki' => 'MediaWikiInstaller', + 'miaoxing' => 'MiaoxingInstaller', + 'microweber' => 'MicroweberInstaller', + 'modulework' => 'MODULEWorkInstaller', + 'modx' => 'ModxInstaller', + 'modxevo' => 'MODXEvoInstaller', + 'moodle' => 'MoodleInstaller', + 'october' => 'OctoberInstaller', + 'ontowiki' => 'OntoWikiInstaller', + 'oxid' => 'OxidInstaller', + 'osclass' => 'OsclassInstaller', + 'pxcms' => 'PxcmsInstaller', + 'phpbb' => 'PhpBBInstaller', + 'pimcore' => 'PimcoreInstaller', + 'piwik' => 'PiwikInstaller', + 'plentymarkets'=> 'PlentymarketsInstaller', + 'ppi' => 'PPIInstaller', + 'puppet' => 'PuppetInstaller', + 'radphp' => 'RadPHPInstaller', + 'phifty' => 'PhiftyInstaller', + 'porto' => 'PortoInstaller', + 'processwire' => 'ProcessWireInstaller', + 'quicksilver' => 'PantheonInstaller', + 'redaxo' => 'RedaxoInstaller', + 'redaxo5' => 'Redaxo5Installer', + 'reindex' => 'ReIndexInstaller', + 'roundcube' => 'RoundcubeInstaller', + 'shopware' => 'ShopwareInstaller', + 'sitedirect' => 'SiteDirectInstaller', + 'silverstripe' => 'SilverStripeInstaller', + 'smf' => 'SMFInstaller', + 'starbug' => 'StarbugInstaller', + 'sydes' => 'SyDESInstaller', + 'sylius' => 'SyliusInstaller', + 'symfony1' => 'Symfony1Installer', + 'tao' => 'TaoInstaller', + 'thelia' => 'TheliaInstaller', + 'tusk' => 'TuskInstaller', + 'typo3-cms' => 'TYPO3CmsInstaller', + 'typo3-flow' => 'TYPO3FlowInstaller', + 'userfrosting' => 'UserFrostingInstaller', + 'vanilla' => 'VanillaInstaller', + 'whmcs' => 'WHMCSInstaller', + 'winter' => 'WinterInstaller', + 'wolfcms' => 'WolfCMSInstaller', + 'wordpress' => 'WordPressInstaller', + 'yawik' => 'YawikInstaller', + 'zend' => 'ZendInstaller', + 'zikula' => 'ZikulaInstaller', + 'prestashop' => 'PrestashopInstaller' + ); + + /** + * Installer constructor. + * + * Disables installers specified in main composer extra installer-disable + * list + * + * @param IOInterface $io + * @param Composer $composer + * @param string $type + * @param Filesystem|null $filesystem + * @param BinaryInstaller|null $binaryInstaller + */ + public function __construct( + IOInterface $io, + Composer $composer, + $type = 'library', + Filesystem $filesystem = null, + BinaryInstaller $binaryInstaller = null + ) { + parent::__construct($io, $composer, $type, $filesystem, + $binaryInstaller); + $this->removeDisabledInstallers(); + } + + /** + * {@inheritDoc} + */ + public function getInstallPath(PackageInterface $package) + { + $type = $package->getType(); + $frameworkType = $this->findFrameworkType($type); + + if ($frameworkType === false) { + throw new \InvalidArgumentException( + 'Sorry the package type of this package is not yet supported.' + ); + } + + $class = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType]; + $installer = new $class($package, $this->composer, $this->getIO()); + + return $installer->getInstallPath($package, $frameworkType); + } + + public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) + { + $installPath = $this->getPackageBasePath($package); + $io = $this->io; + $outputStatus = function () use ($io, $installPath) { + $io->write(sprintf('Deleting %s - %s', $installPath, !file_exists($installPath) ? 'deleted' : 'not deleted')); + }; + + $promise = parent::uninstall($repo, $package); + + // Composer v2 might return a promise here + if ($promise instanceof PromiseInterface) { + return $promise->then($outputStatus); + } + + // If not, execute the code right away as parent::uninstall executed synchronously (composer v1, or v2 without async) + $outputStatus(); + + return null; + } + + /** + * {@inheritDoc} + */ + public function supports($packageType) + { + $frameworkType = $this->findFrameworkType($packageType); + + if ($frameworkType === false) { + return false; + } + + $locationPattern = $this->getLocationPattern($frameworkType); + + return preg_match('#' . $frameworkType . '-' . $locationPattern . '#', $packageType, $matches) === 1; + } + + /** + * Finds a supported framework type if it exists and returns it + * + * @param string $type + * @return string|false + */ + protected function findFrameworkType($type) + { + krsort($this->supportedTypes); + + foreach ($this->supportedTypes as $key => $val) { + if ($key === substr($type, 0, strlen($key))) { + return substr($type, 0, strlen($key)); + } + } + + return false; + } + + /** + * Get the second part of the regular expression to check for support of a + * package type + * + * @param string $frameworkType + * @return string + */ + protected function getLocationPattern($frameworkType) + { + $pattern = false; + if (!empty($this->supportedTypes[$frameworkType])) { + $frameworkClass = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType]; + /** @var BaseInstaller $framework */ + $framework = new $frameworkClass(null, $this->composer, $this->getIO()); + $locations = array_keys($framework->getLocations()); + $pattern = $locations ? '(' . implode('|', $locations) . ')' : false; + } + + return $pattern ? : '(\w+)'; + } + + /** + * Get I/O object + * + * @return IOInterface + */ + private function getIO() + { + return $this->io; + } + + /** + * Look for installers set to be disabled in composer's extra config and + * remove them from the list of supported installers. + * + * Globals: + * - true, "all", and "*" - disable all installers. + * - false - enable all installers (useful with + * wikimedia/composer-merge-plugin or similar) + * + * @return void + */ + protected function removeDisabledInstallers() + { + $extra = $this->composer->getPackage()->getExtra(); + + if (!isset($extra['installer-disable']) || $extra['installer-disable'] === false) { + // No installers are disabled + return; + } + + // Get installers to disable + $disable = $extra['installer-disable']; + + // Ensure $disabled is an array + if (!is_array($disable)) { + $disable = array($disable); + } + + // Check which installers should be disabled + $all = array(true, "all", "*"); + $intersect = array_intersect($all, $disable); + if (!empty($intersect)) { + // Disable all installers + $this->supportedTypes = array(); + } else { + // Disable specified installers + foreach ($disable as $key => $installer) { + if (is_string($installer) && key_exists($installer, $this->supportedTypes)) { + unset($this->supportedTypes[$installer]); + } + } + } + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php b/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php new file mode 100644 index 0000000..c6c1b33 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php @@ -0,0 +1,9 @@ + 'extensions/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php b/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php new file mode 100644 index 0000000..9ee7759 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php @@ -0,0 +1,15 @@ + 'components/{$name}/', + 'module' => 'modules/{$name}/', + 'template' => 'templates/{$name}/', + 'plugin' => 'plugins/{$name}/', + 'library' => 'libraries/{$name}/', + ); + + // TODO: Add inflector for mod_ and com_ names +} diff --git a/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php b/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php new file mode 100644 index 0000000..9cb7b8c --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php @@ -0,0 +1,18 @@ + 'plugins/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php b/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php new file mode 100644 index 0000000..36b2f84 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php @@ -0,0 +1,11 @@ + 'site/plugins/{$name}/', + 'field' => 'site/fields/{$name}/', + 'tag' => 'site/tags/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/KnownInstaller.php b/vendor/composer/installers/src/Composer/Installers/KnownInstaller.php new file mode 100644 index 0000000..c5d08c5 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/KnownInstaller.php @@ -0,0 +1,11 @@ + 'IdnoPlugins/{$name}/', + 'theme' => 'Themes/{$name}/', + 'console' => 'ConsolePlugins/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php b/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php new file mode 100644 index 0000000..7143e23 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php @@ -0,0 +1,10 @@ + 'cms/plugins/{$name}/', + 'media' => 'cms/media/vendor/{$name}/' + ); +} \ No newline at end of file diff --git a/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php b/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php new file mode 100644 index 0000000..dcd6d26 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php b/vendor/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php new file mode 100644 index 0000000..903143a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php @@ -0,0 +1,27 @@ + 'plugins/{$name}/', + 'template' => 'templates/{$name}/', + 'document-template' => 'documents/templates/{$name}/', + 'userpanel-module' => 'userpanel/modules/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + +} diff --git a/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php b/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php new file mode 100644 index 0000000..be4d53a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php @@ -0,0 +1,9 @@ + 'libraries/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php b/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php new file mode 100644 index 0000000..412c0b5 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php @@ -0,0 +1,10 @@ + 'packages/{$vendor}/{$name}/', + 'theme' => 'public/themes/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php b/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php new file mode 100644 index 0000000..47bbd4c --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php @@ -0,0 +1,10 @@ + 'libraries/{$name}/', + 'source' => 'libraries/_source/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php b/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php new file mode 100644 index 0000000..9c2e9fb --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php b/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php new file mode 100644 index 0000000..5a66460 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php @@ -0,0 +1,16 @@ + 'assets/snippets/{$name}/', + 'plugin' => 'assets/plugins/{$name}/', + 'module' => 'assets/modules/{$name}/', + 'template' => 'assets/templates/{$name}/', + 'lib' => 'assets/lib/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php b/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php new file mode 100644 index 0000000..cf18e94 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php @@ -0,0 +1,11 @@ + 'app/design/frontend/{$name}/', + 'skin' => 'skin/frontend/default/{$name}/', + 'library' => 'lib/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MajimaInstaller.php b/vendor/composer/installers/src/Composer/Installers/MajimaInstaller.php new file mode 100644 index 0000000..e463756 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MajimaInstaller.php @@ -0,0 +1,37 @@ + 'plugins/{$name}/', + ); + + /** + * Transforms the names + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + return $this->correctPluginName($vars); + } + + /** + * Change hyphenated names to camelcase + * @param array $vars + * @return array + */ + private function correctPluginName($vars) + { + $camelCasedName = preg_replace_callback('/(-[a-z])/', function ($matches) { + return strtoupper($matches[0][1]); + }, $vars['name']); + $vars['name'] = ucfirst($camelCasedName); + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php b/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php new file mode 100644 index 0000000..ca3cfac --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php @@ -0,0 +1,9 @@ + 'app/packages/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MantisBTInstaller.php b/vendor/composer/installers/src/Composer/Installers/MantisBTInstaller.php new file mode 100644 index 0000000..dadb1db --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MantisBTInstaller.php @@ -0,0 +1,23 @@ + 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php b/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php new file mode 100644 index 0000000..c3dd2b6 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php @@ -0,0 +1,48 @@ + 'plugins/{$name}/', + 'theme' => 'themes/{$name}/', + 'core' => 'app/', + ); + + private function getDirectoryName() + { + $extra = $this->package->getExtra(); + if (!empty($extra['install-directory-name'])) { + return $extra['install-directory-name']; + } + + return $this->toCamelCase($this->package->getPrettyName()); + } + + /** + * @param string $packageName + * + * @return string + */ + private function toCamelCase($packageName) + { + return str_replace(' ', '', ucwords(str_replace('-', ' ', basename($packageName)))); + } + + /** + * Format package name of mautic-plugins to CamelCase + */ + public function inflectPackageVars($vars) + { + + if ($vars['type'] == 'mautic-plugin' || $vars['type'] == 'mautic-theme') { + $directoryName = $this->getDirectoryName(); + $vars['name'] = $directoryName; + } + + return $vars; + } + +} diff --git a/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php b/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php new file mode 100644 index 0000000..30a9167 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php @@ -0,0 +1,33 @@ + 'modules/{$name}/', + ); + + /** + * Format package name. + * + * For package type maya-module, cut off a trailing '-module' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'maya-module') { + return $this->inflectModuleVars($vars); + } + + return $vars; + } + + protected function inflectModuleVars($vars) + { + $vars['name'] = preg_replace('/-module$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php b/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php new file mode 100644 index 0000000..f5a8957 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php @@ -0,0 +1,51 @@ + 'core/', + 'extension' => 'extensions/{$name}/', + 'skin' => 'skins/{$name}/', + ); + + /** + * Format package name. + * + * For package type mediawiki-extension, cut off a trailing '-extension' if present and transform + * to CamelCase keeping existing uppercase chars. + * + * For package type mediawiki-skin, cut off a trailing '-skin' if present. + * + */ + public function inflectPackageVars($vars) + { + + if ($vars['type'] === 'mediawiki-extension') { + return $this->inflectExtensionVars($vars); + } + + if ($vars['type'] === 'mediawiki-skin') { + return $this->inflectSkinVars($vars); + } + + return $vars; + } + + protected function inflectExtensionVars($vars) + { + $vars['name'] = preg_replace('/-extension$/', '', $vars['name']); + $vars['name'] = str_replace('-', ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectSkinVars($vars) + { + $vars['name'] = preg_replace('/-skin$/', '', $vars['name']); + + return $vars; + } + +} diff --git a/vendor/composer/installers/src/Composer/Installers/MiaoxingInstaller.php b/vendor/composer/installers/src/Composer/Installers/MiaoxingInstaller.php new file mode 100644 index 0000000..66d8369 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MiaoxingInstaller.php @@ -0,0 +1,10 @@ + 'plugins/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php b/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php new file mode 100644 index 0000000..b7d9703 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php @@ -0,0 +1,119 @@ + 'userfiles/modules/{$install_item_dir}/', + 'module-skin' => 'userfiles/modules/{$install_item_dir}/templates/', + 'template' => 'userfiles/templates/{$install_item_dir}/', + 'element' => 'userfiles/elements/{$install_item_dir}/', + 'vendor' => 'vendor/{$install_item_dir}/', + 'components' => 'components/{$install_item_dir}/' + ); + + /** + * Format package name. + * + * For package type microweber-module, cut off a trailing '-module' if present + * + * For package type microweber-template, cut off a trailing '-template' if present. + * + */ + public function inflectPackageVars($vars) + { + + + if ($this->package->getTargetDir()) { + $vars['install_item_dir'] = $this->package->getTargetDir(); + } else { + $vars['install_item_dir'] = $vars['name']; + if ($vars['type'] === 'microweber-template') { + return $this->inflectTemplateVars($vars); + } + if ($vars['type'] === 'microweber-templates') { + return $this->inflectTemplatesVars($vars); + } + if ($vars['type'] === 'microweber-core') { + return $this->inflectCoreVars($vars); + } + if ($vars['type'] === 'microweber-adapter') { + return $this->inflectCoreVars($vars); + } + if ($vars['type'] === 'microweber-module') { + return $this->inflectModuleVars($vars); + } + if ($vars['type'] === 'microweber-modules') { + return $this->inflectModulesVars($vars); + } + if ($vars['type'] === 'microweber-skin') { + return $this->inflectSkinVars($vars); + } + if ($vars['type'] === 'microweber-element' or $vars['type'] === 'microweber-elements') { + return $this->inflectElementVars($vars); + } + } + + + return $vars; + } + + protected function inflectTemplateVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-template$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/template-$/', '', $vars['install_item_dir']); + + return $vars; + } + + protected function inflectTemplatesVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-templates$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/templates-$/', '', $vars['install_item_dir']); + + return $vars; + } + + protected function inflectCoreVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-providers$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/-provider$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/-adapter$/', '', $vars['install_item_dir']); + + return $vars; + } + + protected function inflectModuleVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-module$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/module-$/', '', $vars['install_item_dir']); + + return $vars; + } + + protected function inflectModulesVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-modules$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/modules-$/', '', $vars['install_item_dir']); + + return $vars; + } + + protected function inflectSkinVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-skin$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/skin-$/', '', $vars['install_item_dir']); + + return $vars; + } + + protected function inflectElementVars($vars) + { + $vars['install_item_dir'] = preg_replace('/-elements$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/elements-$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/-element$/', '', $vars['install_item_dir']); + $vars['install_item_dir'] = preg_replace('/element-$/', '', $vars['install_item_dir']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/ModxInstaller.php b/vendor/composer/installers/src/Composer/Installers/ModxInstaller.php new file mode 100644 index 0000000..0ee140a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ModxInstaller.php @@ -0,0 +1,12 @@ + 'core/packages/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php b/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php new file mode 100644 index 0000000..0531799 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php @@ -0,0 +1,59 @@ + 'mod/{$name}/', + 'admin_report' => 'admin/report/{$name}/', + 'atto' => 'lib/editor/atto/plugins/{$name}/', + 'tool' => 'admin/tool/{$name}/', + 'assignment' => 'mod/assignment/type/{$name}/', + 'assignsubmission' => 'mod/assign/submission/{$name}/', + 'assignfeedback' => 'mod/assign/feedback/{$name}/', + 'auth' => 'auth/{$name}/', + 'availability' => 'availability/condition/{$name}/', + 'block' => 'blocks/{$name}/', + 'booktool' => 'mod/book/tool/{$name}/', + 'cachestore' => 'cache/stores/{$name}/', + 'cachelock' => 'cache/locks/{$name}/', + 'calendartype' => 'calendar/type/{$name}/', + 'fileconverter' => 'files/converter/{$name}/', + 'format' => 'course/format/{$name}/', + 'coursereport' => 'course/report/{$name}/', + 'customcertelement' => 'mod/customcert/element/{$name}/', + 'datafield' => 'mod/data/field/{$name}/', + 'datapreset' => 'mod/data/preset/{$name}/', + 'editor' => 'lib/editor/{$name}/', + 'enrol' => 'enrol/{$name}/', + 'filter' => 'filter/{$name}/', + 'gradeexport' => 'grade/export/{$name}/', + 'gradeimport' => 'grade/import/{$name}/', + 'gradereport' => 'grade/report/{$name}/', + 'gradingform' => 'grade/grading/form/{$name}/', + 'local' => 'local/{$name}/', + 'logstore' => 'admin/tool/log/store/{$name}/', + 'ltisource' => 'mod/lti/source/{$name}/', + 'ltiservice' => 'mod/lti/service/{$name}/', + 'message' => 'message/output/{$name}/', + 'mnetservice' => 'mnet/service/{$name}/', + 'plagiarism' => 'plagiarism/{$name}/', + 'portfolio' => 'portfolio/{$name}/', + 'qbehaviour' => 'question/behaviour/{$name}/', + 'qformat' => 'question/format/{$name}/', + 'qtype' => 'question/type/{$name}/', + 'quizaccess' => 'mod/quiz/accessrule/{$name}/', + 'quiz' => 'mod/quiz/report/{$name}/', + 'report' => 'report/{$name}/', + 'repository' => 'repository/{$name}/', + 'scormreport' => 'mod/scorm/report/{$name}/', + 'search' => 'search/engine/{$name}/', + 'theme' => 'theme/{$name}/', + 'tinymce' => 'lib/editor/tinymce/plugins/{$name}/', + 'profilefield' => 'user/profile/field/{$name}/', + 'webservice' => 'webservice/{$name}/', + 'workshopallocation' => 'mod/workshop/allocation/{$name}/', + 'workshopeval' => 'mod/workshop/eval/{$name}/', + 'workshopform' => 'mod/workshop/form/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php b/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php new file mode 100644 index 0000000..489ef02 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php @@ -0,0 +1,48 @@ + 'modules/{$name}/', + 'plugin' => 'plugins/{$vendor}/{$name}/', + 'theme' => 'themes/{$vendor}-{$name}/' + ); + + /** + * Format package name. + * + * For package type october-plugin, cut off a trailing '-plugin' if present. + * + * For package type october-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'october-plugin') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'october-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/^oc-|-plugin$/', '', $vars['name']); + $vars['vendor'] = preg_replace('/[^a-z0-9_]/i', '', $vars['vendor']); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/^oc-|-theme$/', '', $vars['name']); + $vars['vendor'] = preg_replace('/[^a-z0-9_]/i', '', $vars['vendor']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php b/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php new file mode 100644 index 0000000..5dd3438 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php @@ -0,0 +1,24 @@ + 'extensions/{$name}/', + 'theme' => 'extensions/themes/{$name}/', + 'translation' => 'extensions/translations/{$name}/', + ); + + /** + * Format package name to lower case and remove ".ontowiki" suffix + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower($vars['name']); + $vars['name'] = preg_replace('/.ontowiki$/', '', $vars['name']); + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + $vars['name'] = preg_replace('/-translation$/', '', $vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/OsclassInstaller.php b/vendor/composer/installers/src/Composer/Installers/OsclassInstaller.php new file mode 100644 index 0000000..3ca7954 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/OsclassInstaller.php @@ -0,0 +1,14 @@ + 'oc-content/plugins/{$name}/', + 'theme' => 'oc-content/themes/{$name}/', + 'language' => 'oc-content/languages/{$name}/', + ); + +} diff --git a/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php b/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php new file mode 100644 index 0000000..1797a22 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php @@ -0,0 +1,59 @@ +.+)\/.+/'; + + protected $locations = array( + 'module' => 'modules/{$name}/', + 'theme' => 'application/views/{$name}/', + 'out' => 'out/{$name}/', + ); + + /** + * getInstallPath + * + * @param PackageInterface $package + * @param string $frameworkType + * @return string + */ + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + $installPath = parent::getInstallPath($package, $frameworkType); + $type = $this->package->getType(); + if ($type === 'oxid-module') { + $this->prepareVendorDirectory($installPath); + } + return $installPath; + } + + /** + * prepareVendorDirectory + * + * Makes sure there is a vendormetadata.php file inside + * the vendor folder if there is a vendor folder. + * + * @param string $installPath + * @return void + */ + protected function prepareVendorDirectory($installPath) + { + $matches = ''; + $hasVendorDirectory = preg_match(self::VENDOR_PATTERN, $installPath, $matches); + if (!$hasVendorDirectory) { + return; + } + + $vendorDirectory = $matches['vendor']; + $vendorPath = getcwd() . '/modules/' . $vendorDirectory; + if (!file_exists($vendorPath)) { + mkdir($vendorPath, 0755, true); + } + + $vendorMetaDataPath = $vendorPath . '/vendormetadata.php'; + touch($vendorMetaDataPath); + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php b/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php new file mode 100644 index 0000000..170136f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/PantheonInstaller.php b/vendor/composer/installers/src/Composer/Installers/PantheonInstaller.php new file mode 100644 index 0000000..439f61a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PantheonInstaller.php @@ -0,0 +1,12 @@ + */ + protected $locations = array( + 'script' => 'web/private/scripts/quicksilver/{$name}', + 'module' => 'web/private/scripts/quicksilver/{$name}', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php b/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php new file mode 100644 index 0000000..4e59a8a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php @@ -0,0 +1,11 @@ + 'bundles/{$name}/', + 'library' => 'libraries/{$name}/', + 'framework' => 'frameworks/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php b/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php new file mode 100644 index 0000000..deb2b77 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php @@ -0,0 +1,11 @@ + 'ext/{$vendor}/{$name}/', + 'language' => 'language/{$name}/', + 'style' => 'styles/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php b/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php new file mode 100644 index 0000000..4781fa6 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php @@ -0,0 +1,21 @@ + 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php b/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php new file mode 100644 index 0000000..c17f457 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php @@ -0,0 +1,32 @@ + 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php b/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php new file mode 100644 index 0000000..903e55f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php @@ -0,0 +1,29 @@ + '{$name}/' + ); + + /** + * Remove hyphen, "plugin" and format to camelcase + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = explode("-", $vars['name']); + foreach ($vars['name'] as $key => $name) { + $vars['name'][$key] = ucfirst($vars['name'][$key]); + if (strcasecmp($name, "Plugin") == 0) { + unset($vars['name'][$key]); + } + } + $vars['name'] = implode("",$vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/Plugin.php b/vendor/composer/installers/src/Composer/Installers/Plugin.php new file mode 100644 index 0000000..e60da0e --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/Plugin.php @@ -0,0 +1,27 @@ +installer = new Installer($io, $composer); + $composer->getInstallationManager()->addInstaller($this->installer); + } + + public function deactivate(Composer $composer, IOInterface $io) + { + $composer->getInstallationManager()->removeInstaller($this->installer); + } + + public function uninstall(Composer $composer, IOInterface $io) + { + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php b/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php new file mode 100644 index 0000000..dbf85e6 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php @@ -0,0 +1,9 @@ + 'app/Containers/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php b/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php new file mode 100644 index 0000000..4c8421e --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php @@ -0,0 +1,10 @@ + 'modules/{$name}/', + 'theme' => 'themes/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/ProcessWireInstaller.php b/vendor/composer/installers/src/Composer/Installers/ProcessWireInstaller.php new file mode 100644 index 0000000..e6834a0 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ProcessWireInstaller.php @@ -0,0 +1,22 @@ + 'site/modules/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php b/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php new file mode 100644 index 0000000..77cc3dd --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php @@ -0,0 +1,11 @@ + 'modules/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/PxcmsInstaller.php b/vendor/composer/installers/src/Composer/Installers/PxcmsInstaller.php new file mode 100644 index 0000000..6551058 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/PxcmsInstaller.php @@ -0,0 +1,63 @@ + 'app/Modules/{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Format package name. + * + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'pxcms-module') { + return $this->inflectModuleVars($vars); + } + + if ($vars['type'] === 'pxcms-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + /** + * For package type pxcms-module, cut off a trailing '-plugin' if present. + * + * return string + */ + protected function inflectModuleVars($vars) + { + $vars['name'] = str_replace('pxcms-', '', $vars['name']); // strip out pxcms- just incase (legacy) + $vars['name'] = str_replace('module-', '', $vars['name']); // strip out module- + $vars['name'] = preg_replace('/-module$/', '', $vars['name']); // strip out -module + $vars['name'] = str_replace('-', '_', $vars['name']); // make -'s be _'s + $vars['name'] = ucwords($vars['name']); // make module name camelcased + + return $vars; + } + + + /** + * For package type pxcms-module, cut off a trailing '-plugin' if present. + * + * return string + */ + protected function inflectThemeVars($vars) + { + $vars['name'] = str_replace('pxcms-', '', $vars['name']); // strip out pxcms- just incase (legacy) + $vars['name'] = str_replace('theme-', '', $vars['name']); // strip out theme- + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); // strip out -theme + $vars['name'] = str_replace('-', '_', $vars['name']); // make -'s be _'s + $vars['name'] = ucwords($vars['name']); // make module name camelcased + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php b/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php new file mode 100644 index 0000000..0f78b5c --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php @@ -0,0 +1,24 @@ + 'src/{$name}/' + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $nameParts = explode('/', $vars['name']); + foreach ($nameParts as &$value) { + $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value)); + $value = str_replace(array('-', '_'), ' ', $value); + $value = str_replace(' ', '', ucwords($value)); + } + $vars['name'] = implode('/', $nameParts); + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php b/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php new file mode 100644 index 0000000..252c733 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php @@ -0,0 +1,10 @@ + 'themes/{$name}/', + 'plugin' => 'plugins/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/Redaxo5Installer.php b/vendor/composer/installers/src/Composer/Installers/Redaxo5Installer.php new file mode 100644 index 0000000..23a2034 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/Redaxo5Installer.php @@ -0,0 +1,10 @@ + 'redaxo/src/addons/{$name}/', + 'bestyle-plugin' => 'redaxo/src/addons/be_style/plugins/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php b/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php new file mode 100644 index 0000000..0954457 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php @@ -0,0 +1,10 @@ + 'redaxo/include/addons/{$name}/', + 'bestyle-plugin' => 'redaxo/include/addons/be_style/plugins/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php b/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php new file mode 100644 index 0000000..d8d795b --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php @@ -0,0 +1,22 @@ + 'plugins/{$name}/', + ); + + /** + * Lowercase name and changes the name to a underscores + * + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(str_replace('-', '_', $vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php b/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php new file mode 100644 index 0000000..1acd3b1 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php @@ -0,0 +1,10 @@ + 'Sources/{$name}/', + 'theme' => 'Themes/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php b/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php new file mode 100644 index 0000000..7d20d27 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php @@ -0,0 +1,60 @@ + 'engine/Shopware/Plugins/Local/Backend/{$name}/', + 'core-plugin' => 'engine/Shopware/Plugins/Local/Core/{$name}/', + 'frontend-plugin' => 'engine/Shopware/Plugins/Local/Frontend/{$name}/', + 'theme' => 'templates/{$name}/', + 'plugin' => 'custom/plugins/{$name}/', + 'frontend-theme' => 'themes/Frontend/{$name}/', + ); + + /** + * Transforms the names + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'shopware-theme') { + return $this->correctThemeName($vars); + } + + return $this->correctPluginName($vars); + } + + /** + * Changes the name to a camelcased combination of vendor and name + * @param array $vars + * @return array + */ + private function correctPluginName($vars) + { + $camelCasedName = preg_replace_callback('/(-[a-z])/', function ($matches) { + return strtoupper($matches[0][1]); + }, $vars['name']); + + $vars['name'] = ucfirst($vars['vendor']) . ucfirst($camelCasedName); + + return $vars; + } + + /** + * Changes the name to a underscore separated name + * @param array $vars + * @return array + */ + private function correctThemeName($vars) + { + $vars['name'] = str_replace('-', '_', $vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php b/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php new file mode 100644 index 0000000..81910e9 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php @@ -0,0 +1,35 @@ + '{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Return the install path based on package type. + * + * Relies on built-in BaseInstaller behaviour with one exception: silverstripe/framework + * must be installed to 'sapphire' and not 'framework' if the version is <3.0.0 + * + * @param PackageInterface $package + * @param string $frameworkType + * @return string + */ + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + if ( + $package->getName() == 'silverstripe/framework' + && preg_match('/^\d+\.\d+\.\d+/', $package->getVersion()) + && version_compare($package->getVersion(), '2.999.999') < 0 + ) { + return $this->templatePath($this->locations['module'], array('name' => 'sapphire')); + } + + return parent::getInstallPath($package, $frameworkType); + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/SiteDirectInstaller.php b/vendor/composer/installers/src/Composer/Installers/SiteDirectInstaller.php new file mode 100644 index 0000000..762d94c --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/SiteDirectInstaller.php @@ -0,0 +1,25 @@ + 'modules/{$vendor}/{$name}/', + 'plugin' => 'plugins/{$vendor}/{$name}/' + ); + + public function inflectPackageVars($vars) + { + return $this->parseVars($vars); + } + + protected function parseVars($vars) + { + $vars['vendor'] = strtolower($vars['vendor']) == 'sitedirect' ? 'SiteDirect' : $vars['vendor']; + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/StarbugInstaller.php b/vendor/composer/installers/src/Composer/Installers/StarbugInstaller.php new file mode 100644 index 0000000..a31c9fd --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/StarbugInstaller.php @@ -0,0 +1,12 @@ + 'modules/{$name}/', + 'theme' => 'themes/{$name}/', + 'custom-module' => 'app/modules/{$name}/', + 'custom-theme' => 'app/themes/{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php b/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php new file mode 100644 index 0000000..8626a9b --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php @@ -0,0 +1,47 @@ + 'app/modules/{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Format module name. + * + * Strip `sydes-` prefix and a trailing '-theme' or '-module' from package name if present. + * + * {@inerhitDoc} + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] == 'sydes-module') { + return $this->inflectModuleVars($vars); + } + + if ($vars['type'] === 'sydes-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + public function inflectModuleVars($vars) + { + $vars['name'] = preg_replace('/(^sydes-|-module$)/i', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/(^sydes-|-theme$)/', '', $vars['name']); + $vars['name'] = strtolower($vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/SyliusInstaller.php b/vendor/composer/installers/src/Composer/Installers/SyliusInstaller.php new file mode 100644 index 0000000..4357a35 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/SyliusInstaller.php @@ -0,0 +1,9 @@ + 'themes/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php b/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php new file mode 100644 index 0000000..1675c4f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php @@ -0,0 +1,26 @@ + + */ +class Symfony1Installer extends BaseInstaller +{ + protected $locations = array( + 'plugin' => 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = preg_replace_callback('/(-[a-z])/', function ($matches) { + return strtoupper($matches[0][1]); + }, $vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php b/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php new file mode 100644 index 0000000..b1663e8 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php @@ -0,0 +1,16 @@ + + */ +class TYPO3CmsInstaller extends BaseInstaller +{ + protected $locations = array( + 'extension' => 'typo3conf/ext/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php b/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php new file mode 100644 index 0000000..42572f4 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php @@ -0,0 +1,38 @@ + 'Packages/Application/{$name}/', + 'framework' => 'Packages/Framework/{$name}/', + 'plugin' => 'Packages/Plugins/{$name}/', + 'site' => 'Packages/Sites/{$name}/', + 'boilerplate' => 'Packages/Boilerplates/{$name}/', + 'build' => 'Build/{$name}/', + ); + + /** + * Modify the package name to be a TYPO3 Flow style key. + * + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + $autoload = $this->package->getAutoload(); + if (isset($autoload['psr-0']) && is_array($autoload['psr-0'])) { + $namespace = key($autoload['psr-0']); + $vars['name'] = str_replace('\\', '.', $namespace); + } + if (isset($autoload['psr-4']) && is_array($autoload['psr-4'])) { + $namespace = key($autoload['psr-4']); + $vars['name'] = rtrim(str_replace('\\', '.', $namespace), '.'); + } + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/TaoInstaller.php b/vendor/composer/installers/src/Composer/Installers/TaoInstaller.php new file mode 100644 index 0000000..4f79a45 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/TaoInstaller.php @@ -0,0 +1,30 @@ + '{$name}' + ); + + public function inflectPackageVars($vars) + { + $extra = $this->package->getExtra(); + + if (array_key_exists(self::EXTRA_TAO_EXTENSION_NAME, $extra)) { + $vars['name'] = $extra[self::EXTRA_TAO_EXTENSION_NAME]; + return $vars; + } + + $vars['name'] = str_replace('extension-', '', $vars['name']); + $vars['name'] = str_replace('-', ' ', $vars['name']); + $vars['name'] = lcfirst(str_replace(' ', '', ucwords($vars['name']))); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php b/vendor/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php new file mode 100644 index 0000000..e20e65b --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php @@ -0,0 +1,32 @@ + 'extensions/{$vendor}/{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Format package name. + * + * Cut off leading 'ti-ext-' or 'ti-theme-' if present. + * Strip vendor name of characters that is not alphanumeric or an underscore + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'tastyigniter-extension') { + $vars['vendor'] = preg_replace('/[^a-z0-9_]/i', '', $vars['vendor']); + $vars['name'] = preg_replace('/^ti-ext-/', '', $vars['name']); + } + + if ($vars['type'] === 'tastyigniter-theme') { + $vars['name'] = preg_replace('/^ti-theme-/', '', $vars['name']); + } + + return $vars; + } +} \ No newline at end of file diff --git a/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php b/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php new file mode 100644 index 0000000..158af52 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php @@ -0,0 +1,12 @@ + 'local/modules/{$name}/', + 'frontoffice-template' => 'templates/frontOffice/{$name}/', + 'backoffice-template' => 'templates/backOffice/{$name}/', + 'email-template' => 'templates/email/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php b/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php new file mode 100644 index 0000000..7c0113b --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php @@ -0,0 +1,14 @@ + + */ + class TuskInstaller extends BaseInstaller + { + protected $locations = array( + 'task' => '.tusk/tasks/{$name}/', + 'command' => '.tusk/commands/{$name}/', + 'asset' => 'assets/tusk/{$name}/', + ); + } diff --git a/vendor/composer/installers/src/Composer/Installers/UserFrostingInstaller.php b/vendor/composer/installers/src/Composer/Installers/UserFrostingInstaller.php new file mode 100644 index 0000000..fcb414a --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/UserFrostingInstaller.php @@ -0,0 +1,9 @@ + 'app/sprinkles/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php b/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php new file mode 100644 index 0000000..24ca645 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php @@ -0,0 +1,10 @@ + 'plugins/{$name}/', + 'theme' => 'themes/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php b/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php new file mode 100644 index 0000000..7d90c5e --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php @@ -0,0 +1,49 @@ + 'src/{$vendor}/{$name}/', + 'theme' => 'themes/{$name}/' + ); + + /** + * Format package name. + * + * For package type vgmcp-bundle, cut off a trailing '-bundle' if present. + * + * For package type vgmcp-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'vgmcp-bundle') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'vgmcp-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-bundle$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php b/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php new file mode 100644 index 0000000..b65dbba --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php @@ -0,0 +1,21 @@ + 'modules/addons/{$vendor}_{$name}/', + 'fraud' => 'modules/fraud/{$vendor}_{$name}/', + 'gateways' => 'modules/gateways/{$vendor}_{$name}/', + 'notifications' => 'modules/notifications/{$vendor}_{$name}/', + 'registrars' => 'modules/registrars/{$vendor}_{$name}/', + 'reports' => 'modules/reports/{$vendor}_{$name}/', + 'security' => 'modules/security/{$vendor}_{$name}/', + 'servers' => 'modules/servers/{$vendor}_{$name}/', + 'social' => 'modules/social/{$vendor}_{$name}/', + 'support' => 'modules/support/{$vendor}_{$name}/', + 'templates' => 'templates/{$vendor}_{$name}/', + 'includes' => 'includes/{$vendor}_{$name}/' + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/WinterInstaller.php b/vendor/composer/installers/src/Composer/Installers/WinterInstaller.php new file mode 100644 index 0000000..cff1bf1 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/WinterInstaller.php @@ -0,0 +1,58 @@ + 'modules/{$name}/', + 'plugin' => 'plugins/{$vendor}/{$name}/', + 'theme' => 'themes/{$name}/' + ); + + /** + * Format package name. + * + * For package type winter-plugin, cut off a trailing '-plugin' if present. + * + * For package type winter-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'winter-module') { + return $this->inflectModuleVars($vars); + } + + if ($vars['type'] === 'winter-plugin') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'winter-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectModuleVars($vars) + { + $vars['name'] = preg_replace('/^wn-|-module$/', '', $vars['name']); + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/^wn-|-plugin$/', '', $vars['name']); + $vars['vendor'] = preg_replace('/[^a-z0-9_]/i', '', $vars['vendor']); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/^wn-|-theme$/', '', $vars['name']); + + return $vars; + } +} diff --git a/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php b/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php new file mode 100644 index 0000000..cb38788 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php @@ -0,0 +1,9 @@ + 'wolf/plugins/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php b/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php new file mode 100644 index 0000000..91c46ad --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php @@ -0,0 +1,12 @@ + 'wp-content/plugins/{$name}/', + 'theme' => 'wp-content/themes/{$name}/', + 'muplugin' => 'wp-content/mu-plugins/{$name}/', + 'dropin' => 'wp-content/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php b/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php new file mode 100644 index 0000000..27f429f --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php @@ -0,0 +1,32 @@ + 'module/{$name}/', + ); + + /** + * Format package name to CamelCase + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} \ No newline at end of file diff --git a/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php b/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php new file mode 100644 index 0000000..bde9bc8 --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php @@ -0,0 +1,11 @@ + 'library/{$name}/', + 'extra' => 'extras/library/{$name}/', + 'module' => 'module/{$name}/', + ); +} diff --git a/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php b/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php new file mode 100644 index 0000000..56cdf5d --- /dev/null +++ b/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php @@ -0,0 +1,10 @@ + 'modules/{$vendor}-{$name}/', + 'theme' => 'themes/{$vendor}-{$name}/' + ); +} diff --git a/vendor/composer/installers/src/bootstrap.php b/vendor/composer/installers/src/bootstrap.php new file mode 100644 index 0000000..0de276e --- /dev/null +++ b/vendor/composer/installers/src/bootstrap.php @@ -0,0 +1,13 @@ += 70100)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/woocommerce/subscriptions-core/.nvmrc b/vendor/woocommerce/subscriptions-core/.nvmrc new file mode 100644 index 0000000..b009dfb --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/.nvmrc @@ -0,0 +1 @@ +lts/* diff --git a/assets/css/about.css b/vendor/woocommerce/subscriptions-core/assets/css/about.css similarity index 63% rename from assets/css/about.css rename to vendor/woocommerce/subscriptions-core/assets/css/about.css index 61667f2..08915f7 100644 --- a/assets/css/about.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/about.css @@ -7,9 +7,9 @@ ul { margin-top: 0; margin-bottom: 1.6em; } -.wcs-badge:before { - font-family: WooCommerce !important; - content: "\e03d"; +.wcs-badge::before { + font-family: 'WooCommerce' !important; + content: '\e03d'; color: #fff; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -26,7 +26,7 @@ ul { vertical-align: middle; } .wcs-badge { - position: relative;; + position: relative; background: #9c5d90; text-rendering: optimizeLegibility; padding-top: 150px; @@ -37,11 +37,11 @@ ul { text-align: center; color: #ddc8d9; margin: 5px 0 0 0; - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,.2); - box-shadow: 0 1px 3px rgba(0,0,0,.2); + -webkit-box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.2 ); + box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.2 ); } .about-wrap h2 { - border-bottom: 1px solid #DDD; + border-bottom: 1px solid #ddd; margin: 0; padding: 1em 0; } @@ -51,12 +51,12 @@ ul { .about-wrap .feature-section { padding-top: 1.6em; padding-bottom: 0.4em; - border-bottom: 1px solid #DDD; + border-bottom: 1px solid #ddd; } .about-wrap .still-more .feature-section { padding-top: 0; padding-bottom: 0.4em; - border-bottom: 1px solid #DDD; + border-bottom: 1px solid #ddd; } .about-wrap .under-the-hood { padding-top: 0; @@ -68,14 +68,14 @@ ul { } .about-wrap .wcs-feature { overflow: visible !important; - *zoom:1; + *zoom: 1; } -.about-wrap .wcs-feature:before, -.about-wrap .wcs-feature:after { - content: " "; +.about-wrap .wcs-feature::before, +.about-wrap .wcs-feature::after { + content: ' '; display: table; } -.about-wrap .wcs-feature:after { +.about-wrap .wcs-feature::after { clear: both; } .about-wrap .two-col .feature-right { @@ -92,40 +92,51 @@ ul { } .woocommerce-message { position: relative; - border-left-color: #cc99c2!important; + border-left-color: #cc99c2 !important; overflow: hidden; } -.woocommerce-message a.button-primary,p.woocommerce-actions a.button-primary, -.woocommerce-message a.button-primary:focus, p.woocommerce-actions a.button-primary:focus, -.woocommerce-message a.button-primary:active, p.woocommerce-actions a.button-primary:active { +.woocommerce-message a.button-primary, +p.woocommerce-actions a.button-primary, +.woocommerce-message a.button-primary:focus, +p.woocommerce-actions a.button-primary:focus, +.woocommerce-message a.button-primary:active, +p.woocommerce-actions a.button-primary:active { background: #b366a4; border-color: #b366a4; - -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15); - box-shadow: inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15); - text-shadow: 0 -1px 1px #b366a4, 1px 0 1px #b366a4, 0 1px 1px #b366a4, -1px 0 1px #b366a4; + -webkit-box-shadow: inset 0 1px 0 rgba( 255, 255, 255, 0.25 ), + 0 1px 0 rgba( 0, 0, 0, 0.15 ); + box-shadow: inset 0 1px 0 rgba( 255, 255, 255, 0.25 ), + 0 1px 0 rgba( 0, 0, 0, 0.15 ); + text-shadow: 0 -1px 1px #b366a4, 1px 0 1px #b366a4, 0 1px 1px #b366a4, + -1px 0 1px #b366a4; color: #fff; text-decoration: none; } -.woocommerce-message a.button-primary:hover,p.woocommerce-actions a.button-primary:hover { +.woocommerce-message a.button-primary:hover, +p.woocommerce-actions a.button-primary:hover { background: #bb77ae; border-color: #aa559a; - -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15); - box-shadow: inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15); + -webkit-box-shadow: inset 0 1px 0 rgba( 255, 255, 255, 0.25 ), + 0 1px 0 rgba( 0, 0, 0, 0.15 ); + box-shadow: inset 0 1px 0 rgba( 255, 255, 255, 0.25 ), + 0 1px 0 rgba( 0, 0, 0, 0.15 ); } -.woocommerce-message a.button-primary:active,p.woocommerce-actions a.button-primary:active { +.woocommerce-message a.button-primary:active, +p.woocommerce-actions a.button-primary:active { background: #aa559a; border-color: #aa559a; } .woocommerce-message a.skip, p.woocommerce-actions a.skip { - opacity: .7; + opacity: 0.7; } -.woocommerce-message .twitter-share-button,p.woocommerce-actions .twitter-share-button { +.woocommerce-message .twitter-share-button, +p.woocommerce-actions .twitter-share-button { vertical-align: middle; margin-left: 3px; } @@ -135,7 +146,7 @@ p.woocommerce-actions { } .woocommerce-about-text { - margin-bottom: 1em!important; + margin-bottom: 1em !important; } .about-wrap .feature-section.three-col .col { @@ -157,13 +168,13 @@ p.woocommerce-actions { float: right !important; } -@media only screen and (max-width: 1200px) { +@media only screen and ( max-width: 1200px ) { .about-wrap .two-col .feature-copy { margin-top: 0; } } -@media only screen and (max-width: 781px) { +@media only screen and ( max-width: 781px ) { .about-wrap .two-col .feature-copy, .about-wrap .feature-section { padding-bottom: 1em; @@ -178,12 +189,12 @@ p.woocommerce-actions { width: 100%; margin: 40px 0 0; padding: 0 0 40px; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); + border-bottom: 1px solid rgba( 0, 0, 0, 0.1 ); } } -@media only screen and (max-width: 500px) { - .about-wrap .wcs-badge:before { +@media only screen and ( max-width: 500px ) { + .about-wrap .wcs-badge::before { width: 100%; } .about-wrap .wcs-badge { @@ -195,4 +206,4 @@ p.woocommerce-actions { width: 100% !important; float: none !important; } -} \ No newline at end of file +} diff --git a/assets/css/admin-order-statuses.css b/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css similarity index 91% rename from assets/css/admin-order-statuses.css rename to vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css index 1368a40..b13581f 100644 --- a/assets/css/admin-order-statuses.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css @@ -10,8 +10,8 @@ color: #777; background: #e5e5e5; border-radius: 4px; - border-bottom: 1px solid rgba(0,0,0,.05); - margin: -.25em 0; + border-bottom: 1px solid rgba( 0, 0, 0, 0.05 ); + margin: -0.25em 0; cursor: inherit !important; white-space: nowrap; max-width: 100%; diff --git a/assets/css/admin.css b/vendor/woocommerce/subscriptions-core/assets/css/admin.css similarity index 62% rename from assets/css/admin.css rename to vendor/woocommerce/subscriptions-core/assets/css/admin.css index 2f6c9ea..3e9a2eb 100644 --- a/assets/css/admin.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/admin.css @@ -5,8 +5,10 @@ .woocommerce-subscriptions-activated a.button-primary:hover { background: #bb77ae; border-color: #aa559a; - -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15); - box-shadow: inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15); + -webkit-box-shadow: inset 0 1px 0 rgba( 255, 255, 255, 0.25 ), + 0 1px 0 rgba( 0, 0, 0, 0.15 ); + box-shadow: inset 0 1px 0 rgba( 255, 255, 255, 0.25 ), + 0 1px 0 rgba( 0, 0, 0, 0.15 ); } .woocommerce-subscriptions-activated a.button-primary:active, .woocommerce-subscriptions-activated a.button-primary:active { @@ -50,10 +52,10 @@ table.wp-list-table span.product-type.variable-subscription { /* Orders List Table */ a.close-subscriptions-search { font-size: 1em; - padding: 0em 0.45em; + padding: 0 0.45em; border-radius: 1.4em; - background: #dd0000; - color: #ffffff; + background: #d00; + color: #fff; margin: -0.3em 0.6em 0 0; } .dismiss-subscriptions-search { @@ -70,43 +72,84 @@ a.close-subscriptions-search { display: block; width: 50%; } -@media only screen and (max-width:1280px){ +@media only screen and ( max-width: 1280px ) { .woocommerce_options_panel ._subscription_price_fields .wrap, .woocommerce_options_panel ._subscription_trial_length_field .wrap, - .woocommerce_options_panel ._subscription_payment_sync_date_day_field .wrap { - width:80%; + .woocommerce_options_panel + ._subscription_payment_sync_date_day_field + .wrap { + width: 80%; } } .woocommerce_options_panel ._subscription_price_fields .wrap input, .woocommerce_options_panel ._subscription_price_fields .wrap select { - width:30.75%; - margin-right:3.8%; + width: 30.75%; + margin-right: 3.8%; } .woocommerce_options_panel ._subscription_trial_length_field .wrap input, .woocommerce_options_panel ._subscription_trial_length_field .wrap select, -.woocommerce_options_panel ._subscription_payment_sync_date_day_field .wrap input, -.woocommerce_options_panel ._subscription_payment_sync_date_day_field .wrap select { - width:48%; - margin-right:3.8%; +.woocommerce_options_panel + ._subscription_payment_sync_date_day_field + .wrap + input, +.woocommerce_options_panel + ._subscription_payment_sync_date_day_field + .wrap + select { + width: 48%; + margin-right: 3.8%; } .woocommerce_options_panel ._subscription_price_fields .wrap .last, .woocommerce_options_panel ._subscription_trial_length_field .wrap .last, -.woocommerce_options_panel ._subscription_payment_sync_date_day_field .wrap .last { - margin-right:0 !important; +.woocommerce_options_panel + ._subscription_payment_sync_date_day_field + .wrap + .last { + margin-right: 0 !important; } .wc-metaboxes-wrapper .wc-metabox table td p._subscription_price_field label, .wc-metaboxes-wrapper .wc-metabox table td p._subscription_period_field label, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_period_interval_field label, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_length_field label, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_period_field label, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_payment_sync_field label { +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_period_interval_field + label, +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_length_field + label, +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_period_field + label, +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_payment_sync_field + label { display: none; } .wc-metaboxes-wrapper .wc-metabox table td p._subscription_price_field input, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_length_field input, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_payment_sync_field input { +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_length_field + input, +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_payment_sync_field + input { width: 5em; } .woocommerce_options_panel #sale-price-period { @@ -117,18 +160,58 @@ a.close-subscriptions-search { width: 7.1em; } -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_price_field { +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_price_field { width: 70px !important; } -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_length_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_sign_up_fee_field { +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_length_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_sign_up_fee_field { width: 100% !important; } -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_price_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_length_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_sign_up_fee_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_length_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_payment_sync_field { +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_price_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_length_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_sign_up_fee_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_length_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_payment_sync_field { padding: 0 0 0 0 !important; margin: 0; } @@ -136,26 +219,67 @@ a.close-subscriptions-search { .wc-metaboxes-wrapper .wc-metabox table td p._subscription_length_field select { width: auto !important; } -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_period_field select { +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_period_field + select { width: 88px !important; } -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_period_field img.help_tip { +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_period_field + img.help_tip { margin-top: 4px; } .wc-metaboxes-wrapper .wc-metabox table td p._subscription_period_field span, .wc-metaboxes-wrapper .wc-metabox table td p._subscription_length_field span, -.wc-metaboxes-wrapper .wc-metabox table td p._subscription_sign_up_fee_field span { +.wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_sign_up_fee_field + span { padding: 5px 0 0 2px; } -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_period_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_length_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_period_interval_field, -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_period_field { +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_period_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_length_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_period_interval_field, +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_period_field { padding: 0 0 0 5px !important; margin: 0; } -#woocommerce-product-data .wc-metaboxes-wrapper .wc-metabox table td p._subscription_trial_period_field select { +#woocommerce-product-data + .wc-metaboxes-wrapper + .wc-metabox + table + td + p._subscription_trial_period_field + select { margin-left: 5px; } @@ -163,7 +287,12 @@ a.close-subscriptions-search { min-width: 180px; } -.wc-metaboxes-wrapper .wc-metabox table tr.variable_subscription_sync td select.wc_input_subscription_payment_sync { +.wc-metaboxes-wrapper + .wc-metabox + table + tr.variable_subscription_sync + td + select.wc_input_subscription_payment_sync { width: auto !important; } @@ -175,7 +304,9 @@ a.close-subscriptions-search { display: none !important; } -#woocommerce-product-data .woocommerce_variation .wcs-can-not-remove-variation-msg { +#woocommerce-product-data + .woocommerce_variation + .wcs-can-not-remove-variation-msg { opacity: 0.5; } @@ -194,8 +325,8 @@ a.close-subscriptions-search { padding: 4px 6px; } -.variable_subscription_trial .form-row input[type=text], -.variable_subscription_pricing .form-row input[type=text], +.variable_subscription_trial .form-row input[type='text'], +.variable_subscription_pricing .form-row input[type='text'], .variable_subscription_trial .form-row select, .variable_subscription_pricing .form-row select { margin: 2px 0 0; @@ -203,23 +334,33 @@ a.close-subscriptions-search { } /* Variation Pricing Fields in WooCommerce 2.3+ */ -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_price, -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_period_interval { +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_price, +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_period_interval { max-width: 33%; float: left; } .variable_subscription_pricing_2_3 .wc_input_subscription_price { clear: left; } -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_period { +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_period { max-width: 34%; float: right; } .variable_subscription_pricing_2_3.variable_subscription_trial p.form-row { margin-bottom: 0; } -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_trial_period, -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_trial_length { +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_trial_period, +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_trial_length { max-width: 50%; } .variable_subscription_pricing_2_3 .wc_input_subscription_trial_period { @@ -229,39 +370,53 @@ a.close-subscriptions-search { .variable_subscription_pricing_2_3 .variable_subscription_trial_sign_up { clear: both; } -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_day { +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_payment_sync_day { max-width: 13%; float: right; } -#variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_month { +#variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_payment_sync_month { max-width: 86%; } -@media screen and (max-width: 1190px) { - #variable_product_options .variable_subscription_pricing_2_3 p._subscription_price_field, - #variable_product_options .variable_subscription_pricing_2_3 p._subscription_length_field { +@media screen and ( max-width: 1190px ) { + #variable_product_options + .variable_subscription_pricing_2_3 + p._subscription_price_field, + #variable_product_options + .variable_subscription_pricing_2_3 + p._subscription_length_field { width: 100%; } - #variable_product_options .variable_subscription_pricing_2_3 p._subscription_price_field { + #variable_product_options + .variable_subscription_pricing_2_3 + p._subscription_price_field { width: 100%; margin-bottom: 0; } - #variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_day { + #variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_payment_sync_day { max-width: 20%; float: right; } - #variable_product_options .variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_month { + #variable_product_options + .variable_subscription_pricing_2_3 + .wc_input_subscription_payment_sync_month { max-width: 78%; } } ._subscription_limit_field .description { display: block; clear: both; - margin-left: 0px; + margin-left: 0; } /* Users Administration Screen */ -.woocommerce_active_subscriber .active-subscriber:before { - content: "\f147"; +.woocommerce_active_subscriber .active-subscriber::before { + content: '\f147'; display: inline-block; -webkit-font-smoothing: antialiased; font: normal 24px/1 'dashicons'; @@ -323,7 +478,9 @@ a.close-subscriptions-search { display: inline-block; font-weight: bold; } -#woocommerce-subscription-schedule .wcs-date-input input[type="text"]:first-of-type { +#woocommerce-subscription-schedule + .wcs-date-input + input[type='text']:first-of-type { width: 8em; } #woocommerce-subscription-schedule img.ui-datepicker-trigger { @@ -345,11 +502,11 @@ a.close-subscriptions-search { height: 1em; width: 1em; display: inline-block; - margin: 0 .5em 0 0; + margin: 0 0.5em 0 0; } -#woocommerce-subscription-schedule .wcs-edit-date:before, -#woocommerce-subscription-schedule .wcs-delete-date:before { - font-family: WooCommerce; +#woocommerce-subscription-schedule .wcs-edit-date::before, +#woocommerce-subscription-schedule .wcs-delete-date::before { + font-family: 'WooCommerce'; speak: none; font-weight: 400; font-variant: normal; @@ -366,17 +523,17 @@ a.close-subscriptions-search { text-align: center; color: #999; } -#woocommerce-subscription-schedule .wcs-edit-date:before { - content: "\e603"; +#woocommerce-subscription-schedule .wcs-edit-date::before { + content: '\e603'; } -#woocommerce-subscription-schedule .wcs-edit-date:hover:before { - color: #555555; +#woocommerce-subscription-schedule .wcs-edit-date:hover::before { + color: #555; } -#woocommerce-subscription-schedule .wcs-delete-date:before { - content: "\e013"; +#woocommerce-subscription-schedule .wcs-delete-date::before { + content: '\e013'; } -#woocommerce-subscription-schedule .wcs-delete-date:hover:before { - color: #AA0000; +#woocommerce-subscription-schedule .wcs-delete-date:hover::before { + color: #a00; } /* Related Orders and Failed Payment Retries Metabox on Edit Subscription/Order Admin Screen */ @@ -479,30 +636,30 @@ table.wp-list-table .subscription_renewal_order { margin: 0 auto; } -table.wp-list-table .subscription_head:after, -table.wp-list-table .subscription_parent_order:after { - font-family: WooCommerce; - content: "\e014"; +table.wp-list-table .subscription_head::after, +table.wp-list-table .subscription_parent_order::after { + font-family: 'WooCommerce'; + content: '\e014'; } -table.wp-list-table .subscription_resubscribe_order:after { - font-family: WooCommerce; - content: "\e014"; +table.wp-list-table .subscription_resubscribe_order::after { + font-family: 'WooCommerce'; + content: '\e014'; color: #999; } -table.wp-list-table .subscription_renewal_order:after { - font-family: Dashicons; - content: "\f321"; +table.wp-list-table .subscription_renewal_order::after { + font-family: 'Dashicons'; + content: '\f321'; } -table.wp-list-table .payment_retry:after { - font-family: WooCommerce; - content: "\e012"; +table.wp-list-table .payment_retry::after { + font-family: 'WooCommerce'; + content: '\e012'; } -table.wp-list-table .subscription_head:after, -table.wp-list-table .subscription_parent_order:after, -table.wp-list-table .subscription_resubscribe_order:after, -table.wp-list-table .subscription_renewal_order:after { +table.wp-list-table .subscription_head::after, +table.wp-list-table .subscription_parent_order::after, +table.wp-list-table .subscription_resubscribe_order::after, +table.wp-list-table .subscription_renewal_order::after { font-weight: 400; margin: 0; text-indent: 0; @@ -519,10 +676,10 @@ table.wp-list-table .subscription_renewal_order:after { left: 0; } -@media only screen and (max-width: 782px) { +@media only screen and ( max-width: 782px ) { table.wp-list-table .subscription_parent_order, table.wp-list-table .subscription_resubscribe_order, - table.wp-list-table .subscription_renewal_order{ + table.wp-list-table .subscription_renewal_order { margin: 0; } table.wp-list-table .column-subscription_relationship { @@ -536,49 +693,56 @@ table.wp-list-table .subscription_renewal_order:after { /* WooCommerce Payment Methods Settings page */ .payment-method-features-info { - font-size: 1.4em; - display: inline-block; - text-indent: -9999px; - position: relative; - height: 1em; - width: 1em + font-size: 1.4em; + display: inline-block; + text-indent: -9999px; + position: relative; + height: 1em; + width: 1em; } .payment-method-features-info::before { - font-family: WooCommerce; - speak: none; - font-weight: 400; - font-variant: normal; - text-transform: none; - line-height: 1; - margin: 0; - text-indent: 0; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - content: "\e018"; - color: #a46497; + font-family: 'WooCommerce'; + speak: none; + font-weight: 400; + font-variant: normal; + text-transform: none; + line-height: 1; + margin: 0; + text-indent: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + content: '\e018'; + color: #a46497; } -table.wc_gateways .renewals .tips{ - margin: 0 0.2em; - display: inline-block; +table.wc_gateways .renewals .tips { + margin: 0 0.2em; + display: inline-block; } /* Hide irrelevant sections on Edit Subscription screen */ -body.post-type-shop_subscription .order_actions #actions optgroup[label='Resend order emails'], +body.post-type-shop_subscription + .order_actions + #actions + optgroup[label='Resend order emails'], body.post-type-shop_subscription .add-items .description.tips, body.post-type-shop_subscription .add-items .button.refund-items { display: none; } -@media only screen and (max-width: 782px) { - #woocommerce-subscription-schedule .wcs-date-input input[type="text"]:first-of-type { +@media only screen and ( max-width: 782px ) { + #woocommerce-subscription-schedule + .wcs-date-input + input[type='text']:first-of-type { width: 45%; } - #woocommerce-subscription-schedule .wcs-date-input input[type="text"]:not(:first-of-type) { + #woocommerce-subscription-schedule + .wcs-date-input + input[type='text']:not( :first-of-type ) { width: 19%; } @@ -592,17 +756,16 @@ body.post-type-shop_subscription .add-items .button.refund-items { margin: 0; } - .post-type-shop_subscription .wp-list-table .column-status:before { + .post-type-shop_subscription .wp-list-table .column-status::before { display: none !important; } .post-type-shop_subscription .wp-list-table .column-orders { text-align: left !important; } - } -span.product-type.variable-subscription:before { - content: "\e003" !important; +span.product-type.variable-subscription::before { + content: '\e003' !important; } /* Settings Page */ @@ -619,12 +782,17 @@ span.product-type.variable-subscription:before { .woocommerce-reports-wide .postbox .chart-legend li a { text-decoration: none; } -.woocommerce-reports-wide .postbox .chart-legend li a .woocommerce-subscriptions-count:after { +.woocommerce-reports-wide + .postbox + .chart-legend + li + a + .woocommerce-subscriptions-count::after { margin-left: 1.5%; font-size: 60%; font-weight: normal; - font-family: dashicons; - content: "\f504"; + font-family: 'dashicons'; + content: '\f504'; } .subscription-status.status-active { background: #c6e1c6; @@ -638,3 +806,15 @@ span.product-type.variable-subscription:before { background: #bfbfbf; color: #737373; } +#wcs_order_price_lock { + display: inline-block; + padding-right: 4px; + margin-top: 3px; +} +#wcs_order_price_lock > label { + font-size: 12px; + vertical-align: initial; +} +#wcs_order_price_lock > .woocommerce-help-tip { + margin: 0 8px 0 2px; +} diff --git a/assets/css/checkout.css b/vendor/woocommerce/subscriptions-core/assets/css/checkout.css similarity index 73% rename from assets/css/checkout.css rename to vendor/woocommerce/subscriptions-core/assets/css/checkout.css index 104dfaa..6679bd3 100644 --- a/assets/css/checkout.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/checkout.css @@ -6,7 +6,7 @@ } .shipping.recurring-total ul li { margin: 0; - padding: .25em 0 .25em 22px; + padding: 0.25em 0 0.25em 22px; text-indent: -22px; list-style: none outside; } @@ -20,8 +20,11 @@ font-weight: 700; } .woocommerce-page table.shop_table_responsive tbody .recurring-totals th { - display:table-cell; + display: table-cell; } -.woocommerce-page table.shop_table_responsive tr.recurring-total td:not([data-title]):before { - content:""; +.woocommerce-page + table.shop_table_responsive + tr.recurring-total + td:not( [data-title] )::before { + content: ''; } diff --git a/assets/css/modal.css b/vendor/woocommerce/subscriptions-core/assets/css/modal.css similarity index 88% rename from assets/css/modal.css rename to vendor/woocommerce/subscriptions-core/assets/css/modal.css index db576d7..808529f 100644 --- a/assets/css/modal.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/modal.css @@ -9,7 +9,7 @@ body.wcs-modal-open { display: flex; align-items: center; justify-content: center; - height: 0vh; + height: 0; background-color: transparent; overflow: hidden; transition: background-color 0.25s ease; @@ -20,12 +20,12 @@ body.wcs-modal-open { position: fixed; width: 100%; height: 100vh; - background-color: rgba(0, 0, 0, 0.5); + background-color: rgba( 0, 0, 0, 0.5 ); transition: background-color 0.25s; } .wcs-modal.open > .content-wrapper { - transform: scale(1); + transform: scale( 1 ); min-width: 30%; max-width: 80%; } @@ -38,17 +38,17 @@ body.wcs-modal-open { justify-content: flex-start; margin: 0; padding: 2em; - background-color: white; + background-color: #fff; border-radius: 0.3em; - transform: scale(0); + transform: scale( 0 ); transition: transform 0.25s; transition-delay: 0.15s; } .wcs-modal .content-wrapper .close { position: absolute; - top: 0px; - right: 0px; + top: 0; + right: 0; z-index: 50; } @@ -95,11 +95,10 @@ body.wcs-modal-open { margin-left: 0.8em; } - /* * Mobile Display Styles */ -@media only screen and (max-width:414px) { +@media only screen and ( max-width: 414px ) { .wcs-modal.open > .content-wrapper { max-width: none; width: 100%; @@ -118,7 +117,7 @@ body.wcs-modal-open { } } -@media only screen and (max-width:320px) { +@media only screen and ( max-width: 320px ) { .wcs-modal.open .content-wrapper .modal-header { height: 7%; } @@ -129,7 +128,7 @@ body.wcs-modal-open { } } -@media only screen and (max-width:768px) { +@media only screen and ( max-width: 768px ) { .wcs-modal.open > .content-wrapper { min-width: 60%; } diff --git a/assets/css/view-subscription.css b/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css similarity index 81% rename from assets/css/view-subscription.css rename to vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css index 8f11982..5c75d7c 100644 --- a/assets/css/view-subscription.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css @@ -1,4 +1,4 @@ -@media only screen and (max-width:768px) { +@media only screen and ( max-width: 768px ) { .subscription_details .button { margin-bottom: 2px; width: 100%; @@ -17,8 +17,8 @@ .subscription-auto-renew-toggle__i { height: 20px; width: 32px; - border: 2px solid #00BA8A; - background-color: #00BA8A; + border: 2px solid #00ba8a; + background-color: #00ba8a; display: inline-block; text-indent: -9999px; border-radius: 10em; @@ -27,8 +27,8 @@ vertical-align: text-top; } -.subscription-auto-renew-toggle__i:before { - content: ""; +.subscription-auto-renew-toggle__i::before { + content: ''; display: block; width: 16px; height: 16px; @@ -44,7 +44,8 @@ background-color: #999; } -.subscription-auto-renew-toggle--off .subscription-auto-renew-toggle__i:before { +.subscription-auto-renew-toggle--off + .subscription-auto-renew-toggle__i::before { right: auto; left: 0; } @@ -71,13 +72,13 @@ .wcs_early_renew_modal_note { position: sticky; - bottom: 0px; + bottom: 0; min-width: 100%; width: 0; } #early_renewal_modal_submit { width: 100%; - font-size:1.4em; + font-size: 1.4em; text-align: center; } diff --git a/assets/css/wcs-upgrade.css b/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css similarity index 72% rename from assets/css/wcs-upgrade.css rename to vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css index b8ad2a2..b4daecb 100644 --- a/assets/css/wcs-upgrade.css +++ b/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css @@ -16,23 +16,23 @@ body { padding: 10px; font-size: 14px; text-align: left; - color: rgb(18, 18, 18); - background: rgb(249, 249, 249); - border: 4px solid rgb(249, 249, 249); + color: rgb( 18, 18, 18 ); + background: rgb( 249, 249, 249 ); + border: 4px solid rgb( 249, 249, 249 ); border-radius: 5px; text-shadow: none; - box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 4px 1px; + box-shadow: rgba( 0, 0, 0, 0.2 ) 0 0 4px 1px; margin-top: -332px; margin-left: 100px; } -.tooltip:after { - content: ""; +.tooltip::after { + content: ''; position: absolute; width: 0; height: 0; border-width: 14px; border-style: solid; - border-color: #F9F9F9 transparent transparent transparent; + border-color: #f9f9f9 transparent transparent transparent; top: 292px; left: 366px; } diff --git a/assets/images/add-edit-subscription-screen.png b/vendor/woocommerce/subscriptions-core/assets/images/add-edit-subscription-screen.png similarity index 100% rename from assets/images/add-edit-subscription-screen.png rename to vendor/woocommerce/subscriptions-core/assets/images/add-edit-subscription-screen.png diff --git a/assets/images/admin-change-payment-method.jpg b/vendor/woocommerce/subscriptions-core/assets/images/admin-change-payment-method.jpg similarity index 100% rename from assets/images/admin-change-payment-method.jpg rename to vendor/woocommerce/subscriptions-core/assets/images/admin-change-payment-method.jpg diff --git a/assets/images/ajax-loader.gif b/vendor/woocommerce/subscriptions-core/assets/images/ajax-loader.gif similarity index 100% rename from assets/images/ajax-loader.gif rename to vendor/woocommerce/subscriptions-core/assets/images/ajax-loader.gif diff --git a/assets/images/ajax-loader@2x.gif b/vendor/woocommerce/subscriptions-core/assets/images/ajax-loader@2x.gif similarity index 100% rename from assets/images/ajax-loader@2x.gif rename to vendor/woocommerce/subscriptions-core/assets/images/ajax-loader@2x.gif diff --git a/assets/images/billing-schedules-meta-box.png b/vendor/woocommerce/subscriptions-core/assets/images/billing-schedules-meta-box.png similarity index 100% rename from assets/images/billing-schedules-meta-box.png rename to vendor/woocommerce/subscriptions-core/assets/images/billing-schedules-meta-box.png diff --git a/assets/images/checkout-recurring-totals.png b/vendor/woocommerce/subscriptions-core/assets/images/checkout-recurring-totals.png similarity index 100% rename from assets/images/checkout-recurring-totals.png rename to vendor/woocommerce/subscriptions-core/assets/images/checkout-recurring-totals.png diff --git a/assets/images/drip-downloadable-content.jpg b/vendor/woocommerce/subscriptions-core/assets/images/drip-downloadable-content.jpg similarity index 100% rename from assets/images/drip-downloadable-content.jpg rename to vendor/woocommerce/subscriptions-core/assets/images/drip-downloadable-content.jpg diff --git a/assets/images/gift-subscription.png b/vendor/woocommerce/subscriptions-core/assets/images/gift-subscription.png similarity index 100% rename from assets/images/gift-subscription.png rename to vendor/woocommerce/subscriptions-core/assets/images/gift-subscription.png diff --git a/assets/images/renewal-retry-settings.png b/vendor/woocommerce/subscriptions-core/assets/images/renewal-retry-settings.png similarity index 100% rename from assets/images/renewal-retry-settings.png rename to vendor/woocommerce/subscriptions-core/assets/images/renewal-retry-settings.png diff --git a/assets/images/subscribe-all-the-things.png b/vendor/woocommerce/subscriptions-core/assets/images/subscribe-all-the-things.png similarity index 100% rename from assets/images/subscribe-all-the-things.png rename to vendor/woocommerce/subscriptions-core/assets/images/subscribe-all-the-things.png diff --git a/assets/images/subscription-reports.png b/vendor/woocommerce/subscriptions-core/assets/images/subscription-reports.png similarity index 100% rename from assets/images/subscription-reports.png rename to vendor/woocommerce/subscriptions-core/assets/images/subscription-reports.png diff --git a/assets/images/subscription-suspended-email.jpg b/vendor/woocommerce/subscriptions-core/assets/images/subscription-suspended-email.jpg similarity index 100% rename from assets/images/subscription-suspended-email.jpg rename to vendor/woocommerce/subscriptions-core/assets/images/subscription-suspended-email.jpg diff --git a/assets/images/subscriptions-importer-exporter.png b/vendor/woocommerce/subscriptions-core/assets/images/subscriptions-importer-exporter.png similarity index 100% rename from assets/images/subscriptions-importer-exporter.png rename to vendor/woocommerce/subscriptions-core/assets/images/subscriptions-importer-exporter.png diff --git a/assets/images/view-subscription.png b/vendor/woocommerce/subscriptions-core/assets/images/view-subscription.png similarity index 100% rename from assets/images/view-subscription.png rename to vendor/woocommerce/subscriptions-core/assets/images/view-subscription.png diff --git a/assets/images/woocommerce_subscriptions_logo.png b/vendor/woocommerce/subscriptions-core/assets/images/woocommerce_subscriptions_logo.png similarity index 100% rename from assets/images/woocommerce_subscriptions_logo.png rename to vendor/woocommerce/subscriptions-core/assets/images/woocommerce_subscriptions_logo.png diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js new file mode 100644 index 0000000..ac18742 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js @@ -0,0 +1,66 @@ +jQuery( function ( $ ) { + if ( arePointersEnabled() ) { + setTimeout( showSubscriptionPointers, 800 ); // give TinyMCE a chance to finish loading + } + + $( 'select#product-type' ).on( 'change', function () { + if ( arePointersEnabled() ) { + $( '#product-type' ).pointer( 'close' ); + } + } ); + + $( + '#_subscription_price, #_subscription_period, #_subscription_length' + ).on( 'change', function () { + if ( arePointersEnabled() ) { + $( '.options_group.subscription_pricing' ).pointer( 'close' ); + $( '#product-type' ).pointer( 'close' ); + } + } ); + + function arePointersEnabled() { + if ( $.getParameterByName( 'subscription_pointers' ) == 'true' ) { + return true; + } else { + return false; + } + } + + function showSubscriptionPointers() { + $( '#product-type' ) + .pointer( { + content: WCSPointers.typePointerContent, + position: { + edge: 'left', + align: 'center', + }, + close: function () { + if ( + $( 'select#product-type' ).val() == + WCSubscriptions.productType + ) { + $( + '.options_group.subscription_pricing:not(".subscription_sync")' + ) + .pointer( { + content: WCSPointers.pricePointerContent, + position: 'bottom', + close: function () { + dismissSubscriptionPointer(); + }, + } ) + .pointer( 'open' ); + } + dismissSubscriptionPointer(); + }, + } ) + .pointer( 'open' ); + } + + function dismissSubscriptionPointer() { + $.post( ajaxurl, { + pointer: 'wcs_pointer', + action: 'dismiss-wp-pointer', + } ); + } +} ); diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js new file mode 100644 index 0000000..21ca486 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js @@ -0,0 +1,1373 @@ +jQuery( function ( $ ) { + $.extend( { + getParameterByName: function ( name ) { + name = name.replace( /[\[]/, '\\[' ).replace( /[\]]/, '\\]' ); + var regexS = '[\\?&]' + name + '=([^&#]*)'; + var regex = new RegExp( regexS ); + var results = regex.exec( window.location.search ); + if ( results == null ) { + return ''; + } else { + return decodeURIComponent( results[ 1 ].replace( /\+/g, ' ' ) ); + } + }, + daysInMonth: function ( month ) { + // Intentionally choose a non-leap year because we want february to have only 28 days. + return new Date( Date.UTC( 2001, month, 0 ) ).getUTCDate(); + }, + showHideSubscriptionMeta: function () { + if ( + $( 'select#product-type' ).val() == WCSubscriptions.productType + ) { + $( '.show_if_simple' ).show(); + $( '.grouping_options' ).hide(); + $( '.options_group.pricing ._regular_price_field' ).hide(); + $( '#sale-price-period' ).show(); + $( '.hide_if_subscription' ).hide(); + $( 'input#_manage_stock' ).trigger( 'change' ); + + if ( 'day' == $( '#_subscription_period' ).val() ) { + $( '.subscription_sync' ).hide(); + } + } else { + $( '.options_group.pricing ._regular_price_field' ).show(); + $( '#sale-price-period' ).hide(); + } + }, + showHideVariableSubscriptionMeta: function () { + // In order for WooCommerce not to show the stock_status_field on variable subscriptions, make sure it has the hide if variable subscription class. + $( 'p.stock_status_field' ).addClass( + 'hide_if_variable-subscription' + ); + + /** + * WC core will hide and show product specific fields in show_and_hide_panels(), however that function only runs on specific events, but not + * when variations are added or loaded. To make sure our subscription-related fields aren't shown by default when a variation is added, we set + * subscription pricing elements "base" cases here. + * + * Note: show() being called on the 'hide_if_' fields and vice versa is intentional. All fields are set in their inverse state first, and + * then shown/hidden by product type afterwards. + */ + $( '.hide_if_variable-subscription' ).show(); + $( '.show_if_variable-subscription' ).hide(); + + if ( $( 'select#product-type' ).val() == 'variable-subscription' ) { + $( 'input#_downloadable' ).prop( 'checked', false ); + $( 'input#_virtual' ).prop( 'checked', false ); + + $( '.show_if_variable' ).show(); + $( '.hide_if_variable' ).hide(); + $( '.show_if_variable-subscription' ).show(); + $( '.hide_if_variable-subscription' ).hide(); + $.showOrHideStockFields(); + + // Make the sale price row full width + $( '.sale_price_dates_fields' ) + .prev( '.form-row' ) + .addClass( 'form-row-full' ) + .removeClass( 'form-row-last' ); + } else { + if ( 'variable' === $( 'select#product-type' ).val() ) { + $( '.show_if_variable-subscription' ).hide(); + $( '.show_if_variable' ).show(); + $( '.hide_if_variable' ).hide(); + $.showOrHideStockFields(); + } + + if ( 'subscription' === $( 'select#product-type' ).val() ) { + $( '.show_if_subscription' ).show(); + $( '.hide_if_subscription' ).hide(); + } + + // Restore the sale price row width to half + $( '.sale_price_dates_fields' ) + .prev( '.form-row' ) + .removeClass( 'form-row-full' ) + .addClass( 'form-row-last' ); + } + }, + showOrHideStockFields: function () { + if ( $( 'input#_manage_stock' ).is( ':checked' ) ) { + $( 'div.stock_fields' ).show(); + } else { + $( 'div.stock_fields' ).hide(); + } + }, + setSubscriptionLengths: function () { + $( + '[name^="_subscription_length"], [name^="variable_subscription_length"]' + ).each( function () { + var $lengthElement = $( this ), + selectedLength = $lengthElement.val(), + hasSelectedLength = false, + matches = $lengthElement + .attr( 'name' ) + .match( /\[(.*?)\]/ ), + periodSelector, + interval; + + if ( matches ) { + // Variation + periodSelector = + '[name="variable_subscription_period[' + + matches[ 1 ] + + ']"]'; + billingInterval = parseInt( + $( + '[name="variable_subscription_period_interval[' + + matches[ 1 ] + + ']"]' + ).val() + ); + } else { + periodSelector = '#_subscription_period'; + billingInterval = parseInt( + $( '#_subscription_period_interval' ).val() + ); + } + + $lengthElement.empty(); + + $.each( + WCSubscriptions.subscriptionLengths[ + $( periodSelector ).val() + ], + function ( length, description ) { + if ( + parseInt( length ) == 0 || + 0 == parseInt( length ) % billingInterval + ) { + $lengthElement.append( + $( '' ) + .attr( 'value', length ) + .text( description ) + ); + } + } + ); + + $lengthElement.children( 'option' ).each( function () { + if ( this.value == selectedLength ) { + hasSelectedLength = true; + return false; + } + } ); + + if ( hasSelectedLength ) { + $lengthElement.val( selectedLength ); + } else { + $lengthElement.val( 0 ); + } + } ); + }, + setTrialPeriods: function () { + $( + '[name^="_subscription_trial_length"], [name^="variable_subscription_trial_length"]' + ).each( function () { + var $trialLengthElement = $( this ), + trialLength = $trialLengthElement.val(), + matches = $trialLengthElement + .attr( 'name' ) + .match( /\[(.*?)\]/ ), + periodStrings; + + if ( matches ) { + // Variation + $trialPeriodElement = $( + '[name="variable_subscription_trial_period[' + + matches[ 1 ] + + ']"]' + ); + } else { + $trialPeriodElement = $( '#_subscription_trial_period' ); + } + + selectedTrialPeriod = $trialPeriodElement.val(); + + $trialPeriodElement.empty(); + + if ( parseInt( trialLength ) == 1 ) { + periodStrings = WCSubscriptions.trialPeriodSingular; + } else { + periodStrings = WCSubscriptions.trialPeriodPlurals; + } + + $.each( periodStrings, function ( key, description ) { + $trialPeriodElement.append( + $( '' ) + .attr( 'value', key ) + .text( description ) + ); + } ); + + $trialPeriodElement.val( selectedTrialPeriod ); + } ); + }, + setSalePeriod: function () { + $( '#sale-price-period' ).fadeOut( 80, function () { + $( '#sale-price-period' ).text( + $( + '#_subscription_period_interval option:selected' + ).text() + + ' ' + + $( '#_subscription_period option:selected' ).text() + ); + $( '#sale-price-period' ).fadeIn( 180 ); + } ); + }, + setSyncOptions: function ( periodField ) { + if ( typeof periodField != 'undefined' ) { + if ( + $( 'select#product-type' ).val() == 'variable-subscription' + ) { + var $container = periodField + .closest( '.woocommerce_variable_attributes' ) + .find( '.variable_subscription_sync' ); + } else { + $container = periodField + .closest( '#general_product_data' ) + .find( '.subscription_sync' ); + } + + var $syncWeekMonthContainer = $container.find( + '.subscription_sync_week_month' + ), + $syncWeekMonthSelect = $syncWeekMonthContainer.find( + 'select' + ), + $syncAnnualContainer = $container.find( + '.subscription_sync_annual' + ), + $varSubField = $container.find( + '[name^="variable_subscription_payment_sync_date"]' + ), + billingPeriod; + + if ( $varSubField.length > 0 ) { + // Variation + var matches = $varSubField + .attr( 'name' ) + .match( /\[(.*?)\]/ ); + $subscriptionPeriodElement = $( + '[name="variable_subscription_period[' + + matches[ 1 ] + + ']"]' + ); + } else { + $subscriptionPeriodElement = $( '#_subscription_period' ); + } + + billingPeriod = $subscriptionPeriodElement.val(); + + if ( 'day' == billingPeriod ) { + $syncWeekMonthSelect.val( 0 ); + $syncAnnualContainer + .find( 'input[type="number"]' ) + .val( 0 ) + .trigger( 'change' ); + } else { + if ( 'year' == billingPeriod ) { + // Make sure the year sync fields are reset + $syncAnnualContainer + .find( 'input[type="number"]' ) + .val( 0 ) + .trigger( 'change' ); + // And the week/month field has no option selected + $syncWeekMonthSelect.val( 0 ); + } else { + // Make sure the year sync value is 0 + $syncAnnualContainer + .find( 'input[type="number"]' ) + .val( 0 ) + .trigger( 'change' ); + + // And the week/month field has the appropriate options + $syncWeekMonthSelect.empty(); + $.each( + WCSubscriptions.syncOptions[ billingPeriod ], + function ( key, description ) { + $syncWeekMonthSelect.append( + $( '' ) + .attr( 'value', key ) + .text( description ) + ); + } + ); + } + } + } + }, + showHideSyncOptions: function () { + if ( + $( '#_subscription_payment_sync_date' ).length > 0 || + $( '.wc_input_subscription_payment_sync' ).length > 0 + ) { + $( '.subscription_sync, .variable_subscription_sync' ).each( + function () { + // loop through all sync field groups + var $syncWeekMonthContainer = $( this ).find( + '.subscription_sync_week_month' + ), + $syncWeekMonthSelect = $syncWeekMonthContainer.find( + 'select' + ), + $syncAnnualContainer = $( this ).find( + '.subscription_sync_annual' + ), + $varSubField = $( this ).find( + '[name^="variable_subscription_payment_sync_date"]' + ), + $slideSwitch = false, // stop the general sync field group sliding down if editing a variable subscription + billingPeriod; + + if ( $varSubField.length > 0 ) { + // Variation + var matches = $varSubField + .attr( 'name' ) + .match( /\[(.*?)\]/ ); + $subscriptionPeriodElement = $( + '[name="variable_subscription_period[' + + matches[ 1 ] + + ']"]' + ); + + if ( + $( 'select#product-type' ).val() == + 'variable-subscription' + ) { + $slideSwitch = true; + } + } else { + $subscriptionPeriodElement = $( + '#_subscription_period' + ); + if ( + $( 'select#product-type' ).val() == + WCSubscriptions.productType + ) { + $slideSwitch = true; + } + } + + billingPeriod = $subscriptionPeriodElement.val(); + + if ( 'day' == billingPeriod ) { + $( this ).slideUp( 400 ); + } else { + if ( $slideSwitch ) { + $( this ).slideDown( 400 ); + if ( 'year' == billingPeriod ) { + // Make sure the year sync fields are visible + $syncAnnualContainer.slideDown( 400 ); + // And the week/month field is hidden + $syncWeekMonthContainer.slideUp( 400 ); + } else { + // Make sure the year sync fields are hidden + $syncAnnualContainer.slideUp( 400 ); + // And the week/month field is visible + $syncWeekMonthContainer.slideDown( 400 ); + } + } + } + } + ); + } + }, + moveSubscriptionVariationFields: function () { + $( '#variable_product_options .variable_subscription_pricing' ) + .not( 'wcs_moved' ) + .each( function () { + var $regularPriceRow = $( this ).siblings( + '.variable_pricing' + ), + $trialSignUpRow = $( this ).siblings( + '.variable_subscription_trial_sign_up' + ), + $saleDatesRow; + + $saleDatesRow = $( this ).siblings( '.variable_pricing' ); + + // Add the subscription price fields above the standard price fields + $( this ).insertBefore( $regularPriceRow ); + + $trialSignUpRow.insertBefore( $( this ) ); + + // Replace the regular price field with the trial period field + $regularPriceRow + .children( ':first' ) + .addClass( 'hide_if_variable-subscription' ); + + $( this ).addClass( 'wcs_moved' ); + } ); + }, + getVariationBulkEditValue: function ( variation_action ) { + var value; + + switch ( variation_action ) { + case 'variable_subscription_period': + case 'variable_subscription_trial_period': + value = prompt( WCSubscriptions.bulkEditPeriodMessage ); + break; + case 'variable_subscription_period_interval': + value = prompt( WCSubscriptions.bulkEditIntervalhMessage ); + break; + case 'variable_subscription_trial_length': + case 'variable_subscription_length': + value = prompt( WCSubscriptions.bulkEditLengthMessage ); + break; + case 'variable_subscription_sign_up_fee': + value = prompt( + woocommerce_admin_meta_boxes_variations.i18n_enter_a_value + ); + value = accounting.unformat( + value, + woocommerce_admin.mon_decimal_point + ); + break; + } + + return value; + }, + disableEnableOneTimeShipping: function () { + var is_synced_or_has_trial = false; + + if ( 'variable-subscription' == $( 'select#product-type' ).val() ) { + var variations = $( + '.woocommerce_variations .woocommerce_variation' + ), + variations_checked = {}, + number_of_pages = $( '.woocommerce_variations' ).attr( + 'data-total_pages' + ); + + $( variations ).each( function () { + var period_field = $( this ).find( + '.wc_input_subscription_period' + ), + variation_index = $( period_field ) + .attr( 'name' ) + .match( /\[(.*?)\]/ ), + variation_id = $( + '[name="variable_post_id[' + + variation_index[ 1 ] + + ']"]' + ).val(), + period = period_field.val(), + trial = $( this ) + .find( '.wc_input_subscription_trial_length' ) + .val(), + sync_date = 0; + + if ( 0 != trial ) { + is_synced_or_has_trial = true; + + // break + return false; + } + + if ( + $( this ).find( '.variable_subscription_sync' ).length + ) { + if ( 'month' == period || 'week' == period ) { + sync_date = $( + '[name="variable_subscription_payment_sync_date[' + + variation_index[ 1 ] + + ']"]' + ).val(); + } else if ( 'year' == period ) { + sync_date = $( + '[name="variable_subscription_payment_sync_date_day[' + + variation_index[ 1 ] + + ']"]' + ).val(); + } + + if ( 0 != sync_date ) { + is_synced_or_has_trial = true; + + // break + return false; + } + } + + variations_checked[ variation_index[ 1 ] ] = variation_id; + } ); + + // if we haven't found a variation synced or with a trial at this point check the backend for other product variations + if ( + ( number_of_pages > 1 || 0 == variations.length ) && + false == is_synced_or_has_trial + ) { + var data = { + action: 'wcs_product_has_trial_or_is_synced', + product_id: + woocommerce_admin_meta_boxes_variations.post_id, + variations_checked: variations_checked, + nonce: WCSubscriptions.oneTimeShippingCheckNonce, + }; + + $.ajax( { + url: WCSubscriptions.ajaxUrl, + data: data, + type: 'POST', + success: function ( response ) { + $( '#_subscription_one_time_shipping' ).prop( + 'disabled', + response.is_synced_or_has_trial + ); + // trigger an event now we have determined the one time shipping availability, in case we need to update the backend + $( + '#_subscription_one_time_shipping' + ).trigger( + 'subscription_one_time_shipping_updated', + [ response.is_synced_or_has_trial ] + ); + }, + } ); + } else { + // trigger an event now we have determined the one time shipping availability, in case we need to update the backend + $( + '#_subscription_one_time_shipping' + ).trigger( 'subscription_one_time_shipping_updated', [ + is_synced_or_has_trial, + ] ); + } + } else { + var trial = $( + '#general_product_data #_subscription_trial_length' + ).val(); + + if ( 0 != trial ) { + is_synced_or_has_trial = true; + } + + if ( + $( '.subscription_sync' ).length && + false == is_synced_or_has_trial + ) { + var period = $( '#_subscription_period' ).val(), + sync_date = 0; + + if ( 'month' == period || 'week' == period ) { + sync_date = $( + '#_subscription_payment_sync_date' + ).val(); + } else if ( 'year' == period ) { + sync_date = $( + '#_subscription_payment_sync_date_day' + ).val(); + } + + if ( 0 != sync_date ) { + is_synced_or_has_trial = true; + } + } + } + + $( '#_subscription_one_time_shipping' ).prop( + 'disabled', + is_synced_or_has_trial + ); + }, + showHideSubscriptionsPanels: function () { + var tab = $( 'div.panel-wrap' ) + .find( 'ul.wc-tabs li' ) + .eq( 0 ) + .find( 'a' ); + var panel = tab.attr( 'href' ); + var visible = $( panel ) + .children( '.options_group' ) + .filter( function () { + return 'none' != $( this ).css( 'display' ); + } ); + if ( 0 != visible.length ) { + tab.trigger( 'click' ).parent().show(); + } + }, + maybeDisableRemoveLinks: function () { + $( '#variable_product_options .woocommerce_variation' ).each( + function () { + var $removeLink = $( this ).find( '.remove_variation' ); + + if ( WCSubscriptions.isLargeSite ) { + $removeLink.addClass( 'wcs_validate_variation_delete' ); + $removeLink.removeClass( 'remove_variation' ); + } else { + var can_remove_variation = + '1' === + $( this ) + .find( 'input.wcs-can-remove-variation' ) + .val(); + var $msg = $( this ).find( + '.wcs-can-not-remove-variation-msg' + ); + + if ( ! can_remove_variation ) { + $msg.text( $removeLink.text() ); + $removeLink.replaceWith( $msg ); + } + } + } + ); + }, + } ); + + $( '.options_group.pricing ._sale_price_field .description' ).prepend( + '' + ); + + // Move the subscription pricing section to the same location as the normal pricing section + $( '.options_group.subscription_pricing' ) + .not( + '.variable_subscription_pricing .options_group.subscription_pricing' + ) + .insertBefore( $( '.options_group.pricing:first' ) ); + $( '.show_if_subscription.clear' ).insertAfter( + $( '.options_group.subscription_pricing' ) + ); + + // Move the subscription variation pricing section to a better location in the DOM on load + if ( + $( '#variable_product_options .variable_subscription_pricing' ).length > + 0 + ) { + $.moveSubscriptionVariationFields(); + } + // When a variation is added + $( '#woocommerce-product-data' ).on( + 'woocommerce_variations_added woocommerce_variations_loaded', + function () { + $.moveSubscriptionVariationFields(); + $.showHideVariableSubscriptionMeta(); + $.showHideSyncOptions(); + $.setSubscriptionLengths(); + } + ); + + if ( $( '.options_group.pricing' ).length > 0 ) { + $.setSalePeriod(); + $.showHideSubscriptionMeta(); + $.showHideVariableSubscriptionMeta(); + $.setSubscriptionLengths(); + $.setTrialPeriods(); + $.showHideSyncOptions(); + $.disableEnableOneTimeShipping(); + $.showHideSubscriptionsPanels(); + } + + // Update subscription ranges when subscription period or interval is changed + $( '#woocommerce-product-data' ).on( + 'change', + '[name^="_subscription_period"], [name^="_subscription_period_interval"], [name^="variable_subscription_period"], [name^="variable_subscription_period_interval"]', + function () { + $.setSubscriptionLengths(); + $.showHideSyncOptions(); + $.setSyncOptions( $( this ) ); + $.setSalePeriod(); + $.disableEnableOneTimeShipping(); + } + ); + + $( '#woocommerce-product-data' ).on( + 'propertychange keyup input paste change', + '[name^="_subscription_trial_length"], [name^="variable_subscription_trial_length"]', + function () { + $.setTrialPeriods(); + } + ); + + // Handles changes to sync date select/input for yearly subscription products. + $( '#woocommerce-product-data' ) + .on( + 'change', + '[name^="_subscription_payment_sync_date_day"], [name^="variable_subscription_payment_sync_date_day"]', + function () { + if ( 0 == $( this ).val() ) { + $( this ) + .siblings( + '[name^="_subscription_payment_sync_date_month"], [name^="variable_subscription_payment_sync_date_month"]' + ) + .val( 0 ); + $( this ).prop( 'disabled', true ); + } + } + ) + .on( + 'change', + '[name^="_subscription_payment_sync_date_month"], [name^="variable_subscription_payment_sync_date_month"]', + function () { + var $syncDayOfMonthInput = $( this ).siblings( + '[name^="_subscription_payment_sync_date_day"], [name^="variable_subscription_payment_sync_date_day"]' + ); + + if ( 0 < $( this ).val() ) { + $syncDayOfMonthInput + .val( 1 ) + .attr( { + step: '1', + min: '1', + max: $.daysInMonth( $( this ).val() ), + } ) + .prop( 'disabled', false ); + } else { + $syncDayOfMonthInput.val( 0 ).trigger( 'change' ); + } + } + ); + + $( 'body' ).on( 'woocommerce-product-type-change', function () { + $.showHideSubscriptionMeta(); + $.showHideVariableSubscriptionMeta(); + $.showHideSyncOptions(); + $.showHideSubscriptionsPanels(); + } ); + + $( 'input#_downloadable, input#_virtual' ).on( 'change', function () { + $.showHideSubscriptionMeta(); + $.showHideVariableSubscriptionMeta(); + } ); + + // Make sure the "Used for variations" checkbox is visible when adding attributes to a variable subscription + $( 'body' ).on( 'woocommerce_added_attribute', function () { + $.showHideVariableSubscriptionMeta(); + } ); + + if ( $.getParameterByName( 'select_subscription' ) == 'true' ) { + $( + 'select#product-type option[value="' + + WCSubscriptions.productType + + '"]' + ).attr( 'selected', 'selected' ); + $( 'select#product-type' ).trigger( 'select' ).trigger( 'change' ); + } + + // Before saving a subscription product, validate the trial period + $( '#post' ).on( 'submit', function ( e ) { + if ( WCSubscriptions.subscriptionLengths !== undefined ) { + var trialLength = $( '#_subscription_trial_length' ).val(), + selectedTrialPeriod = $( '#_subscription_trial_period' ).val(); + + if ( + parseInt( trialLength ) >= + WCSubscriptions.subscriptionLengths[ selectedTrialPeriod ] + .length + ) { + alert( + WCSubscriptions.trialTooLongMessages[ selectedTrialPeriod ] + ); + $( '#ajax-loading' ).hide(); + $( '#publish' ).removeClass( 'button-primary-disabled' ); + e.preventDefault(); + } + } + } ); + + // Notify store manager that deleting an order via the Orders screen also deletes subscriptions associated with the orders + $( '#posts-filter' ).on( 'submit', function () { + if ( + $( '[name="post_type"]' ).val() == 'shop_order' && + ( $( '[name="action"]' ).val() == 'trash' || + $( '[name="action2"]' ).val() == 'trash' ) + ) { + var containsSubscription = false; + $( '[name="post[]"]:checked' ).each( function () { + if ( + true === + $( + '.contains_subscription', + $( '#post-' + $( this ).val() ) + ).data( 'contains_subscription' ) + ) { + containsSubscription = true; + } + return false === containsSubscription; + } ); + if ( containsSubscription ) { + return confirm( WCSubscriptions.bulkTrashWarning ); + } + } + } ); + + $( '.order_actions .submitdelete' ).on( 'click', function () { + if ( $( '[name="contains_subscription"]' ).val() == 'true' ) { + return confirm( WCSubscriptions.trashWarning ); + } + } ); + + $( '#variable_product_options' ).on( + 'click', + '.delete.wcs-can-not-remove-variation-msg', + function ( e ) { + e.preventDefault(); + e.stopPropagation(); + } + ); + + // Notify the store manager that trashing an order via the admin orders table row action also deletes the associated subscription if it exists + $( '.row-actions .submitdelete' ).on( 'click', function () { + var order = $( this ).closest( '.type-shop_order' ).attr( 'id' ); + + if ( + true === + $( '.contains_subscription', $( '#' + order ) ).data( + 'contains_subscription' + ) + ) { + return confirm( WCSubscriptions.trashWarning ); + } + } ); + + // Editing a variable product + $( '#variable_product_options' ).on( + 'change', + '[name^="variable_regular_price"]', + function () { + var matches = $( this ) + .attr( 'name' ) + .match( /\[(.*?)\]/ ); + + if ( matches ) { + var loopIndex = matches[ 1 ]; + $( + '[name="variable_subscription_price[' + loopIndex + ']"]' + ).val( $( this ).val() ); + } + } + ); + + // Editing a variable product + $( '#variable_product_options' ).on( + 'change', + '[name^="variable_subscription_price"]', + function () { + var matches = $( this ) + .attr( 'name' ) + .match( /\[(.*?)\]/ ); + + if ( matches ) { + var loopIndex = matches[ 1 ]; + $( '[name="variable_regular_price[' + loopIndex + ']"]' ).val( + $( this ).val() + ); + } + } + ); + + // Update hidden regular price when subscription price is update on simple products + $( '#general_product_data' ).on( + 'change', + '[name^="_subscription_price"]', + function () { + $( '[name="_regular_price"]' ).val( $( this ).val() ); + } + ); + + // Notify store manager that deleting an user via the Users screen also removed them from any subscriptions. + $( '.users-php .submitdelete' ).on( 'click', function () { + return confirm( WCSubscriptions.deleteUserWarning ); + } ); + + // WC 2.4+ variation bulk edit handling + $( 'select.variation_actions' ).on( + 'variable_subscription_sign_up_fee_ajax_data variable_subscription_period_interval_ajax_data variable_subscription_period_ajax_data variable_subscription_trial_period_ajax_data variable_subscription_trial_length_ajax_data variable_subscription_length_ajax_data', + function ( event, data ) { + bulk_action = event.type.replace( /_ajax_data/g, '' ); + value = $.getVariationBulkEditValue( bulk_action ); + + if ( 'variable_subscription_trial_length' == bulk_action ) { + // After variations have their trial length bulk updated in the backend, flag the One Time Shipping field as needing to be updated + $( '#_subscription_one_time_shipping' ).addClass( + 'wcs_ots_needs_update' + ); + } + + if ( value != null ) { + data.value = value; + } + return data; + } + ); + + var $allowSwitching = $( + document.getElementById( + 'woocommerce_subscriptions_allow_switching' + ) + ), + $syncRenewals = $( + document.getElementById( 'woocommerce_subscriptions_sync_payments' ) + ); + + // We're on the Subscriptions settings page + if ( $allowSwitching.length > 0 ) { + var allowSwitchingEnabled = $allowSwitching.find( 'input:checked' ) + .length, + $switchSettingsRows = $allowSwitching + .parents( 'tr' ) + .siblings( 'tr' ), + $prorateFirstRenewal = $( + document.getElementById( + 'woocommerce_subscriptions_prorate_synced_payments' + ) + ), + $syncRows = $syncRenewals.parents( 'tr' ).siblings( 'tr' ), + $daysNoFeeRow = $( + document.getElementById( + 'woocommerce_subscriptions_days_no_fee' + ) + ).parents( 'tr' ), + $suspensionExtensionRow = $( + '#woocommerce_subscriptions_recoup_suspension' + ).parents( 'tr' ); + + // No animation for initial hiding when switching is disabled. + if ( 0 === allowSwitchingEnabled ) { + $switchSettingsRows.hide(); + } + + $allowSwitching.find( 'input' ).on( 'change', function () { + var isEnabled = $allowSwitching.find( 'input:checked' ).length; + + if ( 0 === isEnabled ) { + $switchSettingsRows.fadeOut(); + } else if ( 0 === allowSwitchingEnabled ) { + // switching was previously disabled, so settings will be hidden + $switchSettingsRows.fadeIn(); + } + allowSwitchingEnabled = isEnabled; + } ); + + // Show/hide suspension extension setting + $( '#woocommerce_subscriptions_max_customer_suspensions' ) + .on( 'change', function () { + if ( $( this ).val() > 0 ) { + $suspensionExtensionRow.show(); + } else { + $suspensionExtensionRow.hide(); + } + } ) + .trigger( 'change' ); + + // No animation when initially hiding prorated rows. + if ( ! $syncRenewals.is( ':checked' ) ) { + $syncRows.hide(); + } else if ( 'recurring' !== $prorateFirstRenewal.val() ) { + $daysNoFeeRow.hide(); + } + + // Animate showing and hiding the synchronization rows. + $syncRenewals.on( 'change', function () { + if ( $( this ).is( ':checked' ) ) { + $syncRows.not( $daysNoFeeRow ).fadeIn(); + $prorateFirstRenewal.trigger( 'change' ); + } else { + $syncRows.fadeOut(); + } + } ); + + // Watch the Prorate First Renewal field for changes. + $prorateFirstRenewal.on( 'change', function () { + if ( 'recurring' === $( this ).val() ) { + $daysNoFeeRow.fadeIn(); + } else { + $daysNoFeeRow.fadeOut(); + } + } ); + } + + // Don't display the variation notice for variable subscription products + $( 'body' ).on( 'woocommerce-display-product-type-alert', function ( + e, + select_val + ) { + if ( select_val == 'variable-subscription' ) { + return false; + } + } ); + + $( '.wcs_payment_method_selector' ).on( 'change', function () { + var payment_method = $( this ).val(); + + $( '.wcs_payment_method_meta_fields' ).hide(); + $( '#wcs_' + payment_method + '_fields' ).show(); + } ); + + // After variations have been saved/updated in the backend, flag the One Time Shipping field as needing to be updated + $( '#woocommerce-product-data' ).on( + 'woocommerce_variations_saved', + function () { + $( '#_subscription_one_time_shipping' ).addClass( + 'wcs_ots_needs_update' + ); + } + ); + + // After variations have been loaded and if the One Time Shipping field needs updating, check if One Time Shipping is still available + $( '#woocommerce-product-data' ).on( + 'woocommerce_variations_loaded', + function () { + if ( $( '.wcs_ots_needs_update' ).length ) { + $.disableEnableOneTimeShipping(); + } + } + ); + + // After variations have been loaded, check which ones are tied to subscriptions to prevent them from being deleted. + $( '#woocommerce-product-data' ).on( + 'woocommerce_variations_loaded', + function () { + $.maybeDisableRemoveLinks(); + } + ); + + // Validate the request to remove a variation on large sites. + $( document ).on( 'click', '.wcs_validate_variation_delete', function ( + e + ) { + e.preventDefault(); + + // Prevent WC from expanding the meta box on click. + $( this ) + .closest( '.wc-metaboxes-wrapper' ) + .find( '.wc-metabox > .wc-metabox-content' ) + .hide(); + + var variation_id = $( this ).attr( 'rel' ); + var container = $( '#woocommerce-product-data' ); + var data = { + action: 'wcs_validate_variation_deletion', + variation_id: variation_id, + nonce: WCSubscriptions.nonce, + }; + + // Block the UI while we check if the variation can be deleted. + container.block( { + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6, + }, + } ); + + $.ajax( { + url: WCSubscriptions.ajaxUrl, + data: data, + type: 'POST', + success: function ( response ) { + container.unblock(); + + remove_link = $( + '.wcs_validate_variation_delete[rel=' + variation_id + ']' + ); + + if ( 'yes' === response.can_remove ) { + // Restore the remove variation link and click it. + remove_link.addClass( 'remove_variation' ); + remove_link.removeClass( 'wcs_validate_variation_delete' ); + remove_link.trigger( 'click' ); + } else { + alert( WCSubscriptions.variationDeleteFailMessage ); + + // Now that we know this variation cannot be deleted, block the remove variation link. + msg = $( + '.wcs-can-not-remove-variation-msg[rel=' + + variation_id + + ']' + ); + msg.text( remove_link.text() ); + remove_link.replaceWith( msg ); + } + }, + error: function () { + container.unblock(); + alert( WCSubscriptions.variationDeleteErrorMessage ); + }, + } ); + + return false; + } ); + + // Triggered by $.disableEnableOneTimeShipping() after One Time shipping has been enabled or disabled for variations. + // If the One Time Shipping field needs updating, send the ajax request to update the product setting in the backend + $( '#_subscription_one_time_shipping' ).on( + 'subscription_one_time_shipping_updated', + function ( event, is_synced_or_has_trial ) { + if ( $( '.wcs_ots_needs_update' ).length ) { + var data = { + action: 'wcs_update_one_time_shipping', + product_id: woocommerce_admin_meta_boxes_variations.post_id, + one_time_shipping_enabled: ! is_synced_or_has_trial, + one_time_shipping_selected: $( + '#_subscription_one_time_shipping' + ).prop( 'checked' ), + nonce: WCSubscriptions.oneTimeShippingCheckNonce, + }; + + $.ajax( { + url: WCSubscriptions.ajaxUrl, + data: data, + type: 'POST', + success: function ( response ) { + // remove the flag requiring the one time shipping field to be updated + $( '#_subscription_one_time_shipping' ).removeClass( + 'wcs_ots_needs_update' + ); + $( '#_subscription_one_time_shipping' ).prop( + 'checked', + response.one_time_shipping == 'yes' ? true : false + ); + }, + } ); + } + } + ); + + $( '#general_product_data, #variable_product_options' ).on( + 'change', + '[class^="wc_input_subscription_payment_sync"], [class^="wc_input_subscription_trial_length"]', + function () { + $.disableEnableOneTimeShipping(); + } + ); + + /** + * Prevents removal of variations in use by a subscription. + */ + var wcs_prevent_variation_removal = { + init: function () { + if ( 0 === $( '#woocommerce-product-data' ).length ) { + return; + } + + $( 'body' ).on( + 'woocommerce-product-type-change', + this.product_type_change + ); + $( '#variable_product_options' ).on( + 'reload', + this.product_type_change + ); + $( 'select.variation_actions' ).on( + 'delete_all_no_subscriptions_ajax_data', + this.bulk_action_data + ); + this.product_type_change(); + }, + + product_type_change: function () { + var product_type = $( '#product-type' ).val(); + var $variation_actions = $( 'select.variation_actions' ); + var $delete_all = $variation_actions.find( + 'option[value="delete_all"], option[value="delete_all_no_subscriptions"]' + ); + + if ( + 'variable-subscription' === product_type && + 'delete_all' === $delete_all.val() + ) { + $delete_all + .data( 'wcs_original_wc_label', $delete_all.text() ) + .attr( 'value', 'delete_all_no_subscriptions' ) + .text( WCSubscriptions.bulkDeleteOptionLabel ); + } else if ( + 'variable-subscription' !== product_type && + 'delete_all_no_subscriptions' === $delete_all.val() + ) { + $delete_all + .text( $delete_all.data( 'wcs_original_wc_label' ) ) + .attr( 'value', 'delete_all' ); + } + }, + + bulk_action_data: function ( event, data ) { + if ( + window.confirm( + woocommerce_admin_meta_boxes_variations.i18n_delete_all_variations + ) + ) { + if ( + window.confirm( + woocommerce_admin_meta_boxes_variations.i18n_last_warning + ) + ) { + data.allowed = true; + + // do_variation_action() in woocommerce/assets/js/admin/meta-boxes-product-variation.js doesn't + // allow us to do anything after the AJAX request, so we need to listen to all AJAX requests for a + // little while to update the quantity and refresh the variation list. + $( document ).on( + 'ajaxComplete', + wcs_prevent_variation_removal.update_qty_after_removal + ); + } + } + + return data; + }, + + update_qty_after_removal: function ( event, jqXHR, ajaxOptions ) { + var $variations = $( + '#variable_product_options .woocommerce_variations' + ); + var removed; + + // Not our bulk edit request. Ignore. + if ( + -1 === + ajaxOptions.data.indexOf( + 'action=woocommerce_bulk_edit_variations' + ) || + -1 === + ajaxOptions.data.indexOf( + 'bulk_action=delete_all_no_subscriptions' + ) + ) { + return; + } + + // Unbind so this doesn't get called every time an AJAX request is performed. + $( document ).off( + 'ajaxComplete', + wcs_prevent_variation_removal.update_qty_after_removal + ); + + // Update variation quantity. + removed = + 'OK' === jqXHR.statusText + ? parseInt( jqXHR.responseText, 10 ) + : 0; + $variations.attr( + 'data-total', + Math.max( + 0, + parseInt( $variations.attr( 'data-total' ), 10 ) - removed + ) + ); + $( '#variable_product_options' ).trigger( 'reload' ); + }, + }; + wcs_prevent_variation_removal.init(); + + /* + * Prevents changing of the product type for subscription products in use by a subscription. + */ + var wcs_prevent_product_type_change = { + init: function () { + if ( 'yes' !== WCSubscriptions.productHasSubscriptions ) { + return; + } + + var $select = $( 'select#product-type' ); + var $options = $select.find( 'option' ); + var $selection = $options.filter( 'option:selected' ); + + if ( + 'subscription' !== $selection.val() && + 'variable-subscription' !== $selection.val() + ) { + return; + } + + $options.not( $selection ).prop( 'disabled', true ); + $select + .addClass( 'tips' ) + .attr( 'data-tip', WCSubscriptions.productTypeWarning ); + }, + }; + wcs_prevent_product_type_change.init(); + + /* + * Handles enabling and disabling PayPal Standard for Subscriptions. + */ + var wcs_paypal_standard_settings = { + init: function () { + if ( 0 === $( '#woocommerce_paypal_enabled' ).length ) { + return; + } + + $( '#woocommerce_paypal_enabled' ).on( + 'change', + this.paypal_enabled_change + ); + $( '#woocommerce_paypal_enabled_for_subscriptions' ).on( + 'change', + this.paypal_for_subscriptions_enabled + ); + this.paypal_enabled_change(); + }, + + /** + * Show and hide the enable PayPal for Subscriptions checkbox when PayPal is enabled or disabled. + */ + paypal_enabled_change: function () { + var $enabled_for_subscriptions_element = $( + '#woocommerce_paypal_enabled_for_subscriptions' + ).closest( 'tr' ); + + if ( $( '#woocommerce_paypal_enabled' ).is( ':checked' ) ) { + $enabled_for_subscriptions_element.show(); + } else { + $enabled_for_subscriptions_element.hide(); + } + }, + + /** + * Display a confirm dialog when PayPal for Subscriptions is enabled (checked). + */ + paypal_for_subscriptions_enabled: function () { + if ( + $( this ).is( ':checked' ) && + ! confirm( WCSubscriptions.enablePayPalWarning ) + ) { + $( this ).prop( 'checked', false ); + } + }, + }; + wcs_paypal_standard_settings.init(); + + /* + * Handles showing and hiding subscription related settings on the Accounts and Privacy settings page + */ + var wcs_accounts_and_privacy_settings = { + init: function () { + if ( + 0 === + $( '#woocommerce_enable_signup_and_login_from_checkout' ).length + ) { + return; + } + + $( '#woocommerce_enable_signup_and_login_from_checkout' ).on( + 'change', + this.checkout_account_creation_changed + ); + this.checkout_account_creation_changed( 'no_animation' ); + }, + + /** + * Hides or shows the setting to allow customers to create an account on checkout while purchasing subscriptions. + */ + checkout_account_creation_changed: function ( + animation_behaviour = '' + ) { + var subscription_registration_setting = $( + '#woocommerce_enable_signup_from_checkout_for_subscriptions' + ).closest( 'fieldset' ); + var hide_function = + animation_behaviour === 'no_animation' ? 'hide' : 'slideUp'; + var show_function = + animation_behaviour === 'no_animation' ? 'show' : 'slideDown'; + + // This setting isn't necessary if the store already allows registration on checkout. + if ( + $( '#woocommerce_enable_signup_and_login_from_checkout' ).is( + ':checked' + ) + ) { + subscription_registration_setting[ hide_function ](); + } else { + subscription_registration_setting[ show_function ](); + } + }, + }; + wcs_accounts_and_privacy_settings.init(); +} ); diff --git a/assets/js/admin/jstz.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js similarity index 100% rename from assets/js/admin/jstz.js rename to vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js diff --git a/assets/js/admin/jstz.min.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js similarity index 100% rename from assets/js/admin/jstz.min.js rename to vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js diff --git a/assets/js/admin/meta-boxes-coupon.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js similarity index 81% rename from assets/js/admin/meta-boxes-coupon.js rename to vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js index 85218f6..03e2964 100644 --- a/assets/js/admin/meta-boxes-coupon.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js @@ -1,4 +1,4 @@ -jQuery( document ).ready( function( $ ) { +jQuery( function ( $ ) { 'use strict'; var renewals_field = document.querySelector( '.wcs_number_payments_field' ), @@ -9,13 +9,14 @@ jQuery( document ).ready( function( $ ) { * @type {{init: function, type_options: function, move_field: function}} */ var wcs_meta_boxes_coupon_actions = { - /** * Initialize variation actions. */ - init: function() { + init: function () { if ( renewals_field ) { - $( document.getElementById( 'discount_type' ) ).on( 'change', this.type_options ).change(); + $( document.getElementById( 'discount_type' ) ) + .on( 'change', this.type_options ) + .trigger( 'change' ); this.move_field(); } }, @@ -23,7 +24,7 @@ jQuery( document ).ready( function( $ ) { /** * Show/hide fields by coupon type options. */ - type_options: function() { + type_options: function () { var select_val = $( this ).val(); switch ( select_val ) { @@ -41,12 +42,12 @@ jQuery( document ).ready( function( $ ) { /** * Move the renewal form field in the DOM to a better location. */ - move_field: function() { + move_field: function () { var parent = document.getElementById( 'general_coupon_data' ), shipping = parent.querySelector( '.free_shipping_field' ); parent.insertBefore( renewals_field, shipping ); - } + }, }; wcs_meta_boxes_coupon_actions.init(); diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js new file mode 100644 index 0000000..4b68461 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js @@ -0,0 +1,354 @@ +jQuery( function ( $ ) { + var timezone = jstz.determine(); + + // Display the timezone for date changes + $( '#wcs-timezone' ).text( timezone.name() ); + + // Display times in client's timezone (based on UTC) + $( '.woocommerce-subscriptions.date-picker' ).each( function () { + var $date_input = $( this ), + date_type = $date_input.attr( 'id' ), + $hour_input = $( '#' + date_type + '_hour' ), + $minute_input = $( '#' + date_type + '_minute' ), + time = $( '#' + date_type + '_timestamp_utc' ).val(), + date = moment.unix( time ); + + if ( time > 0 ) { + date.local(); + $date_input.val( + date.year() + + '-' + + zeroise( date.months() + 1 ) + + '-' + + date.format( 'DD' ) + ); + $hour_input.val( date.format( 'HH' ) ); + $minute_input.val( date.format( 'mm' ) ); + } + } ); + + // Make sure start date picker is in the past + $( '.woocommerce-subscriptions.date-picker#start' ).datepicker( + 'option', + 'maxDate', + moment().toDate() + ); + + // Make sure other date pickers are in the future + $( '.woocommerce-subscriptions.date-picker:not(#start)' ).datepicker( + 'option', + 'minDate', + moment().add( 1, 'hours' ).toDate() + ); + + // Validate date when hour/minute inputs change + $( '[name$="_hour"], [name$="_minute"]' ).on( 'change', function () { + $( + '#' + + $( this ) + .attr( 'name' ) + .replace( '_hour', '' ) + .replace( '_minute', '' ) + ).trigger( 'change' ); + } ); + + // Validate entire date + $( '.woocommerce-subscriptions.date-picker' ).on( 'change', function () { + // The date was deleted, clear hour/minute inputs values and set the UTC timestamp to 0 + if ( '' == $( this ).val() ) { + $( '#' + $( this ).attr( 'id' ) + '_hour' ).val( '' ); + $( '#' + $( this ).attr( 'id' ) + '_minute' ).val( '' ); + $( '#' + $( this ).attr( 'id' ) + '_timestamp_utc' ).val( 0 ); + return; + } + + var time_now = moment(), + one_hour_from_now = moment().add( 1, 'hours' ), + minimum_date = wcs_admin_meta_boxes.is_duplicate_site + ? moment().add( 2, 'minutes' ) + : one_hour_from_now, + $date_input = $( this ), + date_type = $date_input.attr( 'id' ), + date_pieces = $date_input.val().split( '-' ), + $hour_input = $( '#' + date_type + '_hour' ), + $minute_input = $( '#' + date_type + '_minute' ), + chosen_hour = + 0 == $hour_input.val().length + ? one_hour_from_now.format( 'HH' ) + : $hour_input.val(), + chosen_minute = + 0 == $minute_input.val().length + ? one_hour_from_now.format( 'mm' ) + : $minute_input.val(), + chosen_date = moment( { + years: date_pieces[ 0 ], + months: date_pieces[ 1 ] - 1, + date: date_pieces[ 2 ], + hours: chosen_hour, + minutes: chosen_minute, + seconds: one_hour_from_now.format( 'ss' ), + } ); + + // Make sure start date is before now. + if ( + 'start' == date_type && + false === chosen_date.isBefore( time_now ) + ) { + alert( wcs_admin_meta_boxes.i18n_start_date_notice ); + $date_input.val( + time_now.year() + + '-' + + zeroise( time_now.months() + 1 ) + + '-' + + time_now.format( 'DD' ) + ); + $hour_input.val( time_now.format( 'HH' ) ); + $minute_input.val( time_now.format( 'mm' ) ); + } + + // Make sure trial end and next payment are after start date + if ( + ( 'trial_end' == date_type || 'next_payment' == date_type ) && + '' != $( '#start_timestamp_utc' ).val() + ) { + var change_date = false, + start = moment.unix( $( '#start_timestamp_utc' ).val() ); + + // Make sure trial end is after start date + if ( + 'trial_end' == date_type && + chosen_date.isBefore( start, 'minute' ) + ) { + if ( 'trial_end' == date_type ) { + alert( wcs_admin_meta_boxes.i18n_trial_end_start_notice ); + } else if ( 'next_payment' == date_type ) { + alert( + wcs_admin_meta_boxes.i18n_next_payment_start_notice + ); + } + + // Change the date + $date_input.val( + start.year() + + '-' + + zeroise( start.months() + 1 ) + + '-' + + start.format( 'DD' ) + ); + $hour_input.val( start.format( 'HH' ) ); + $minute_input.val( start.format( 'mm' ) ); + } + } + + // Make sure next payment is after trial end + if ( + 'next_payment' == date_type && + '' != $( '#trial_end_timestamp_utc' ).val() + ) { + var trial_end = moment.unix( + $( '#trial_end_timestamp_utc' ).val() + ); + + if ( chosen_date.isBefore( trial_end, 'minute' ) ) { + alert( wcs_admin_meta_boxes.i18n_next_payment_trial_notice ); + $date_input.val( + trial_end.year() + + '-' + + zeroise( trial_end.months() + 1 ) + + '-' + + trial_end.format( 'DD' ) + ); + $hour_input.val( trial_end.format( 'HH' ) ); + $minute_input.val( trial_end.format( 'mm' ) ); + } + } + + // Make sure trial end is before next payment and expiration is after next payment date + else if ( + ( 'trial_end' == date_type || 'end' == date_type ) && + '' != $( '#next_payment' ).val() + ) { + var change_date = false, + next_payment = moment.unix( + $( '#next_payment_timestamp_utc' ).val() + ); + + // Make sure trial end is before or equal to next payment + if ( + 'trial_end' == date_type && + next_payment.isBefore( chosen_date, 'minute' ) + ) { + alert( wcs_admin_meta_boxes.i18n_trial_end_next_notice ); + change_date = true; + } + // Make sure end date is after next payment date + else if ( + 'end' == date_type && + chosen_date.isBefore( next_payment, 'minute' ) + ) { + alert( wcs_admin_meta_boxes.i18n_end_date_notice ); + change_date = true; + } + + if ( true === change_date ) { + $date_input.val( + next_payment.year() + + '-' + + zeroise( next_payment.months() + 1 ) + + '-' + + next_payment.format( 'DD' ) + ); + $hour_input.val( next_payment.format( 'HH' ) ); + $minute_input.val( next_payment.format( 'mm' ) ); + } + } + + // Make sure the date is more than an hour in the future + if ( + 'trial_end' != date_type && + 'start' != date_type && + chosen_date.unix() < minimum_date.unix() + ) { + alert( wcs_admin_meta_boxes.i18n_past_date_notice ); + + // Set date to current day + $date_input.val( + one_hour_from_now.year() + + '-' + + zeroise( one_hour_from_now.months() + 1 ) + + '-' + + one_hour_from_now.format( 'DD' ) + ); + + // Set time if current time is in the past + if ( + chosen_date.hours() < one_hour_from_now.hours() || + ( chosen_date.hours() == one_hour_from_now.hours() && + chosen_date.minutes() < one_hour_from_now.minutes() ) + ) { + $hour_input.val( one_hour_from_now.format( 'HH' ) ); + $minute_input.val( one_hour_from_now.format( 'mm' ) ); + } + } + + if ( 0 == $hour_input.val().length ) { + $hour_input.val( one_hour_from_now.format( 'HH' ) ); + } + + if ( 0 == $minute_input.val().length ) { + $minute_input.val( one_hour_from_now.format( 'mm' ) ); + } + + // Update the UTC timestamp sent to the server + date_pieces = $date_input.val().split( '-' ); + + $( '#' + date_type + '_timestamp_utc' ).val( + moment( { + years: date_pieces[ 0 ], + months: date_pieces[ 1 ] - 1, + date: date_pieces[ 2 ], + hours: $hour_input.val(), + minutes: $minute_input.val(), + seconds: one_hour_from_now.format( 'ss' ), + } ) + .utc() + .unix() + ); + + $( 'body' ).trigger( 'wcs-updated-date', date_type ); + } ); + + function zeroise( val ) { + return val > 9 ? val : '0' + val; + } + + if ( $( '#parent-order-id' ).is( 'select' ) ) { + wcs_update_parent_order_options(); + + $( '#customer_user' ).on( 'change', wcs_update_parent_order_options ); + } + + function wcs_update_parent_order_options() { + // Get user ID to load orders for + var user_id = $( '#customer_user' ).val(); + + if ( ! user_id ) { + return false; + } + + var data = { + user_id: user_id, + action: 'wcs_get_customer_orders', + security: wcs_admin_meta_boxes.get_customer_orders_nonce, + }; + + $( '#parent-order-id' ) + .siblings( '.select2-container' ) + .block( { + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6, + }, + } ); + + $.ajax( { + url: WCSubscriptions.ajaxUrl, + data: data, + type: 'POST', + success: function ( response ) { + if ( response ) { + var $orderlist = $( '#parent-order-id' ); + + $( '#parent-order-id' ).select2( 'val', '' ); + + $orderlist.empty(); // remove old options + + $orderlist.append( + $( '' ) + .attr( 'value', '' ) + .text( 'Select an order' ) + ); + + $.each( response, function ( order_id, order_number ) { + $orderlist.append( + $( '' ) + .attr( 'value', order_id ) + .text( order_number ) + ); + } ); + + $( '#parent-order-id' ) + .siblings( '.select2-container' ) + .unblock(); + } + }, + } ); + return false; + } + + $( 'body.post-type-shop_subscription #post' ).on( 'submit', function () { + if ( + 'wcs_process_renewal' == + $( + "body.post-type-shop_subscription select[name='wc_order_action']" + ).val() + ) { + return confirm( + wcs_admin_meta_boxes.process_renewal_action_warning + ); + } + } ); + + $( 'body.post-type-shop_subscription #post' ).on( 'submit', function () { + if ( + typeof wcs_admin_meta_boxes.change_payment_method_warning != + 'undefined' && + wcs_admin_meta_boxes.payment_method != $( '#_payment_method' ).val() + ) { + return confirm( + wcs_admin_meta_boxes.change_payment_method_warning + ); + } + } ); +} ); diff --git a/assets/js/admin/moment.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js similarity index 100% rename from assets/js/admin/moment.js rename to vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js diff --git a/assets/js/admin/moment.min.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js similarity index 100% rename from assets/js/admin/moment.min.js rename to vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js new file mode 100644 index 0000000..2de0863 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js @@ -0,0 +1,109 @@ +jQuery( function( $ ) { + + /** + * If the WC core validation passes (errors removed), check our own validation. + */ + $( document.body ).on( 'wc_remove_error_tip', function( e, element, removed_error_type ) { + var product_type = $( '#product-type' ).val(); + + if ( 'subscription' !== product_type && 'variable-subscription' !== product_type ) { + return; + } + + // We're only interested in the product's recurring price and sale price input. + if ( 'subscription' === product_type && ! $( element ).is( '#_subscription_price' ) && ! $( element ).is( '#_sale_price' ) ) { + return; + } + + if ( 'variable-subscription' === product_type && ! $( element ).hasClass( 'wc_input_subscription_price' ) && ! $( element ).is( '.wc_input_price[name^=variable_sale_price]' ) ) { + return; + } + + // Reformat the product price - remove the decimal place separator and remove excess decimal places. + var price = accounting.unformat( $( element ).val(), wcs_gateway_restrictions.decimal_point_separator ); + price = accounting.formatNumber( price, wcs_gateway_restrictions.number_of_decimal_places, '' ); + + // Error types to validate. + var zero_error = 'i18n_zero_subscription_error'; + var displaying_zero_error = element.parent().find( '.wc_error_tip, .' + zero_error ).length !== 0; + + // Check if the product price is 0 or less. + if ( 0 >= price ) { + $( document.body ).triggerHandler( 'wc_subscriptions_add_error_tip', [ element, zero_error ] ); + displaying_zero_error = true; + } else if ( displaying_zero_error && removed_error_type !== zero_error ) { + $( document.body ).triggerHandler( 'wc_remove_error_tip', [ element, zero_error ] ); + displaying_zero_error = false; + } + + // Check if the product price is below the amount that can be processed by the payment gateway. + if ( ! displaying_zero_error && 'undefined' !== typeof wcs_gateway_restrictions.minimum_subscription_amount ) { + var below_minimum_error = 'i18n_below_minimum_subscription_error'; + var displaying_minimum_error = element.parent().find( '.wc_error_tip, .' + below_minimum_error ).length !== 0; + + if ( parseFloat( wcs_gateway_restrictions.minimum_subscription_amount ) > parseFloat( price ) ) { + $( document.body ).triggerHandler( 'wc_subscriptions_add_error_tip', [ element, below_minimum_error ] ); + displaying_minimum_error = true; + } else if ( displaying_minimum_error && removed_error_type !== below_minimum_error ) { + $( document.body ).triggerHandler( 'wc_remove_error_tip', [ element, below_minimum_error ] ); + displaying_minimum_error = false; + } + } + } ); + + /** + * Validate the recurring price or sale price field on element change event or when a validate event is triggered. + */ + $( document.body ).on( 'change wc_subscriptions_validate_zero_recurring_price', '#_subscription_price, #_sale_price, .wc_input_subscription_price, .wc_input_price[name^=variable_sale_price]', function() { + var product_type = $( '#product-type' ).val(); + + if ( 'subscription' !== product_type && 'variable-subscription' !== product_type ) { + return; + } + + // Reformat the product price - remove the decimal place separator and remove excess decimal places. + var price = accounting.unformat( $( this ).val(), wcs_gateway_restrictions.decimal_point_separator ); + price = accounting.formatNumber( price, wcs_gateway_restrictions.number_of_decimal_places ); + + if ( 0 >= price ) { + $( this ).val( '' ); + } + } ); + + /** + * When the product type is changed to a subscription product type, validate generic product sale price elements. + */ + $( document.body ).on( 'change', '#product-type', function() { + var product_type = $( '#product-type' ).val(); + + if ( 'subscription' !== product_type && 'variable-subscription' !== product_type ) { + return; + } + + $( '#_sale_price, .wc_input_price[name^=variable_sale_price]' ).each( function() { + $( this ).trigger( 'wc_subscriptions_validate_zero_recurring_price' ); + }); + } ); + + + /** + * Displays a WC error tip against an element for a given error type. + * + * Based on the WC core `wc_add_error_tip` handler callback in woocommerce_admin.js. + */ + $( document.body ).on( 'wc_subscriptions_add_error_tip', function( e, element, error_type ) { + var offset = element.position(); + + // Remove any error that is already being shown before adding a new one. + if ( element.parent().find( '.wc_error_tip' ).length !== 0 ) { + element.parent().find( '.wc_error_tip' ).remove(); + } + + element.after( '
    ' + wcs_gateway_restrictions[ error_type ] + '
    ' ); + element.parent().find( '.wc_error_tip' ) + .css( 'left', offset.left + element.width() - ( element.width() / 2 ) - ( $( '.wc_error_tip' ).width() / 2 ) ) + .css( 'top', offset.top + element.height() ) + .fadeIn( '100' ); + + }) +} ); diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js new file mode 100644 index 0000000..650fa84 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js @@ -0,0 +1,43 @@ +jQuery( function ( $ ) { + $( 'body.post-type-shop_order #post' ).on( 'submit', function () { + if ( + 'wcs_retry_renewal_payment' == + $( + "body.post-type-shop_order select[name='wc_order_action']" + ).val() + ) { + return confirm( + wcs_admin_order_meta_boxes.retry_renewal_payment_action_warning + ); + } + } ); + + $( document ).on( 'change', '#wcs-order-price-lock', function () { + // Block the checkbox element while we update the order. + $( '#wcs_order_price_lock' ).block( { + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6, + }, + } ); + + var data = { + wcs_order_price_lock: $( '#wcs-order-price-lock' ).is( ':checked' ) + ? 'yes' + : 'no', + order_id: $( '#post_ID' ).val(), + action: 'wcs_order_price_lock', + woocommerce_meta_nonce: $( '#woocommerce_meta_nonce' ).val(), + }; + + $.ajax( { + type: 'post', + url: woocommerce_admin_meta_boxes.ajax_url, + data: data, + complete: function () { + $( '#wcs_order_price_lock' ).unblock(); + }, + } ); + } ); +} ); diff --git a/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js b/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js new file mode 100755 index 0000000..4373038 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js @@ -0,0 +1,22 @@ +jQuery( function ( $ ) { + /** + * Displays an appropriate error message when the delete token button is clicked for a token used by subscriptions. + */ + $( '.wcs_deletion_error' ).on( 'click', function ( e ) { + e.preventDefault(); + + // Use the href to determine which notice needs to be displayed. + if ( '#choose_default' === $( this ).attr( 'href' ) ) { + $( '#wcs_delete_token_warning' ) + .find( 'li' ) + .html( wcs_payment_methods.choose_default_error ); + } else { + $( '#wcs_delete_token_warning' ) + .find( 'li' ) + .html( wcs_payment_methods.add_method_error ); + } + + // Display the notice. + $( '#wcs_delete_token_warning' ).slideDown(); + } ); +} ); diff --git a/assets/js/frontend/single-product.js b/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js similarity index 69% rename from assets/js/frontend/single-product.js rename to vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js index 12b0d6c..b63eb63 100644 --- a/assets/js/frontend/single-product.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js @@ -1,14 +1,14 @@ -(function ( document, $ ) { - +( function ( document, $ ) { var $cache = {}; /** * Cache our DOM selectors. */ function generate_cache() { - $cache.document = $( document ); - $cache.first_payment_date = $( '.first-payment-date' ); - $cache.is_variable_subscription = 0 < $( 'div.product-type-variable-subscription' ).length; + $cache.document = $( document ); + $cache.first_payment_date = $( '.first-payment-date' ); + $cache.is_variable_subscription = + 0 < $( 'div.product-type-variable-subscription' ).length; } /** @@ -16,7 +16,10 @@ */ function attach_events() { if ( $cache.is_variable_subscription ) { - $cache.document.on( 'found_variation', update_first_payment_element ); + $cache.document.on( + 'found_variation', + update_first_payment_element + ); $cache.document.on( 'reset_data', clear_first_payment_element ); } } @@ -47,6 +50,4 @@ } $( init ); - -})( document, jQuery ); - +} )( document, jQuery ); diff --git a/assets/js/frontend/view-subscription.js b/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js similarity index 54% rename from assets/js/frontend/view-subscription.js rename to vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js index ff44e63..557b0b9 100644 --- a/assets/js/frontend/view-subscription.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js @@ -1,30 +1,33 @@ -jQuery( document ).ready( function( $ ) { +jQuery( function ( $ ) { // Auto Renewal Toggle var $toggleContainer = $( '.wcs-auto-renew-toggle' ); - var $toggle = $( '.subscription-auto-renew-toggle', $toggleContainer ); - var $icon = $toggle.find( 'i' ); - var txtColor = null; - var $paymentMethod = $( '.subscription-payment-method' ); + var $toggle = $( '.subscription-auto-renew-toggle', $toggleContainer ); + var $icon = $toggle.find( 'i' ); + var txtColor = null; + var $paymentMethod = $( '.subscription-payment-method' ); // Early Renewal - var $early_renewal_modal_submit = $( '#early_renewal_modal_submit' ); + var $early_renewal_modal_submit = $( '#early_renewal_modal_submit' ); var $early_renewal_modal_content = $( '.wcs-modal > .content-wrapper' ); function getTxtColor() { - if ( !txtColor && ( $icon && $icon.length ) ) { - txtColor = getComputedStyle( $icon[0] ).color; + if ( ! txtColor && $icon && $icon.length ) { + txtColor = getComputedStyle( $icon[ 0 ] ).color; } return txtColor; } function maybeApplyColor() { - if ( $toggle.hasClass( 'subscription-auto-renew-toggle--on' ) && $icon.length ) { - $icon[0].style.backgroundColor = getTxtColor(); - $icon[0].style.borderColor = getTxtColor(); - } else if( $icon.length ) { - $icon[0].style.backgroundColor = null; - $icon[0].style.borderColor = null; + if ( + $toggle.hasClass( 'subscription-auto-renew-toggle--on' ) && + $icon.length + ) { + $icon[ 0 ].style.backgroundColor = getTxtColor(); + $icon[ 0 ].style.borderColor = getTxtColor(); + } else if ( $icon.length ) { + $icon[ 0 ].style.backgroundColor = null; + $icon[ 0 ].style.borderColor = null; } } @@ -36,42 +39,44 @@ jQuery( document ).ready( function( $ ) { e.preventDefault(); // Remove focus from the toggle element. - $toggle.blur(); + $toggle.trigger( 'blur' ); // Ignore the request if the toggle is disabled. if ( $toggle.hasClass( 'subscription-auto-renew-toggle--disabled' ) ) { return; } - var ajaxHandler = function( action ) { + var ajaxHandler = function ( action ) { var data = { subscription_id: WCSViewSubscription.subscription_id, - action: action, - security: WCSViewSubscription.auto_renew_nonce, + action: action, + security: WCSViewSubscription.auto_renew_nonce, }; // While we're waiting for an AJAX response, block the toggle element to prevent spamming the server. blockToggle(); - $.ajax({ - url: WCSViewSubscription.ajax_url, + $.ajax( { + url: WCSViewSubscription.ajax_url, data: data, type: 'POST', - success: function( result ) { + success: function ( result ) { if ( result.payment_method ) { - $paymentMethod.fadeOut( function() { - $paymentMethod.html( result.payment_method ).fadeIn(); - }); + $paymentMethod.fadeOut( function () { + $paymentMethod + .html( result.payment_method ) + .fadeIn(); + } ); } - if ( undefined !== result.is_manual ) { + if ( undefined !== result.is_manual ) { $paymentMethod.data( 'is_manual', result.is_manual ); } }, - error: function( jqxhr, status, exception ) { + error: function ( jqxhr, status, exception ) { alert( 'Exception:', exception ); }, - complete: unblockToggle - }); + complete: unblockToggle, + } ); }; // Enable auto-renew @@ -80,11 +85,15 @@ jQuery( document ).ready( function( $ ) { if ( WCSViewSubscription.has_payment_gateway ) { ajaxHandler( 'wcs_enable_auto_renew' ); displayToggleOn(); - } else if ( window.confirm( WCSViewSubscription.add_payment_method_msg ) ) { // else add payment method - window.location.href = WCSViewSubscription.add_payment_method_url; + } else if ( + window.confirm( WCSViewSubscription.add_payment_method_msg ) + ) { + // else add payment method + window.location.href = + WCSViewSubscription.add_payment_method_url; } - - } else { // Disable auto-renew + } else { + // Disable auto-renew ajaxHandler( 'wcs_disable_auto_renew' ); displayToggleOff(); } @@ -94,19 +103,23 @@ jQuery( document ).ready( function( $ ) { function displayToggleOn() { $icon.removeClass( 'fa-toggle-off' ).addClass( 'fa-toggle-on' ); - $toggle.removeClass( 'subscription-auto-renew-toggle--off' ).addClass( 'subscription-auto-renew-toggle--on' ); + $toggle + .removeClass( 'subscription-auto-renew-toggle--off' ) + .addClass( 'subscription-auto-renew-toggle--on' ); } function displayToggleOff() { $icon.removeClass( 'fa-toggle-on' ).addClass( 'fa-toggle-off' ); - $toggle.removeClass( 'subscription-auto-renew-toggle--on' ).addClass( 'subscription-auto-renew-toggle--off' ); + $toggle + .removeClass( 'subscription-auto-renew-toggle--on' ) + .addClass( 'subscription-auto-renew-toggle--off' ); } function blockToggle() { - $toggleContainer.block({ + $toggleContainer.block( { message: null, - overlayCSS: { opacity: 0.0 } - }); + overlayCSS: { opacity: 0.0 }, + } ); } function unblockToggle() { @@ -114,24 +127,27 @@ jQuery( document ).ready( function( $ ) { } function blockEarlyRenewalModal() { - $early_renewal_modal_content.block({ + $early_renewal_modal_content.block( { message: null, overlayCSS: { background: '#fff', - opacity: 0.6 - } - }); + opacity: 0.6, + }, + } ); } // Don't display the early renewal modal for manual subscriptions, they will need to renew via the checkout. function shouldShowEarlyRenewalModal( event ) { // We're only interested in requests to show the early renewal modal. - if ( '.subscription_renewal_early' !== $( event.modal ).data( 'modal-trigger' ) ) { + if ( + '.subscription_renewal_early' !== + $( event.modal ).data( 'modal-trigger' ) + ) { return; } return $paymentMethod.data( 'is_manual' ) === 'no'; - }; + } $toggle.on( 'click', onToggle ); maybeApplyColor(); @@ -139,5 +155,4 @@ jQuery( document ).ready( function( $ ) { $early_renewal_modal_submit.on( 'click', blockEarlyRenewalModal ); $( document ).on( 'wcs_show_modal', shouldShowEarlyRenewalModal ); -}); - +} ); diff --git a/assets/js/frontend/wcs-cart.js b/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js similarity index 66% rename from assets/js/frontend/wcs-cart.js rename to vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js index 834ca9f..237c38d 100755 --- a/assets/js/frontend/wcs-cart.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js @@ -2,20 +2,24 @@ function hide_non_applicable_coupons() { var coupon_elements = document.getElementsByClassName( 'cart-discount' ); for ( var i = 0; i < coupon_elements.length; i++ ) { - if ( 0 !== coupon_elements[i].getElementsByClassName( 'wcs-hidden-coupon' ).length ) { - coupon_elements[i].style.display = 'none'; + if ( + 0 !== + coupon_elements[ i ].getElementsByClassName( 'wcs-hidden-coupon' ) + .length + ) { + coupon_elements[ i ].style.display = 'none'; } } } hide_non_applicable_coupons(); -jQuery( document ).ready( function( $ ) { - $( document.body ).on( 'updated_cart_totals updated_checkout', function() { +jQuery( function ( $ ) { + $( document.body ).on( 'updated_cart_totals updated_checkout', function () { hide_non_applicable_coupons(); } ); - $( '.payment_methods [name="payment_method"]' ).click( function() { + $( '.payment_methods [name="payment_method"]' ).on( 'click', function () { if ( $( this ).hasClass( 'supports-payment-method-changes' ) ) { $( '.update-all-subscriptions-payment-method-wrap' ).show(); } else { diff --git a/assets/js/modal.js b/vendor/woocommerce/subscriptions-core/assets/js/modal.js similarity index 88% rename from assets/js/modal.js rename to vendor/woocommerce/subscriptions-core/assets/js/modal.js index 68e9932..4e9a584 100644 --- a/assets/js/modal.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/modal.js @@ -1,14 +1,14 @@ -jQuery( document ).ready( function( $ ) { +jQuery( function ( $ ) { const modals = $( '.wcs-modal' ); // Resize all open modals on window resize. $( window ).on( 'resize', resizeModals ); // Initialize modals - $( modals ).each( function() { + $( modals ).each( function () { trigger = $( this ).data( 'modal-trigger' ); - $( trigger ).click( { modal: this }, show_modal ); - }); + $( trigger ).on( 'click', { modal: this }, show_modal ); + } ); /** * Displays the modal linked to a click event. @@ -28,9 +28,9 @@ jQuery( document ).ready( function( $ ) { event.preventDefault(); const contentWrapper = modal.find( '.content-wrapper' ); - const close = modal.find( '.close' ); + const close = modal.find( '.close' ); - modal.focus(); + modal.trigger( 'focus' ); modal.addClass( 'open' ); resizeModal( modal ); @@ -43,9 +43,9 @@ jQuery( document ).ready( function( $ ) { contentWrapper.on( 'click', ( e ) => e.stopPropagation() ); // Close the modal if the escape key is pressed. - modal.on( 'keyup', function( e ) { + modal.on( 'keyup', function ( e ) { if ( 27 === e.keyCode ) { - close_modal( modal ) + close_modal( modal ); } } ); } @@ -73,7 +73,7 @@ jQuery( document ).ready( function( $ ) { */ function should_show_modal( modal ) { // Allow third-parties to filter whether the modal should be displayed. - var event = jQuery.Event( 'wcs_show_modal' ); + var event = jQuery.Event( 'wcs_show_modal' ); event.modal = modal; $( document ).trigger( event ); @@ -86,13 +86,13 @@ jQuery( document ).ready( function( $ ) { * Resize all open modals to fit the display. */ function resizeModals() { - $( modals ).each( function() { + $( modals ).each( function () { if ( ! $( this ).hasClass( 'open' ) ) { return; } resizeModal( this ); - }); + } ); } /** @@ -111,4 +111,4 @@ jQuery( document ).ready( function( $ ) { modal_container.css( 'height', '90%' ); } } -}); +} ); diff --git a/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js b/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js new file mode 100644 index 0000000..83d2f48 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js @@ -0,0 +1,273 @@ +jQuery( function ( $ ) { + var upgrade_start_time = null, + total_subscriptions = wcs_update_script_data.subscription_count; + + $( '#update-messages' ).slideUp(); + $( '#upgrade-step-3' ).slideUp(); + + $( 'form#subscriptions-upgrade' ).on( 'submit', function ( e ) { + $( '#update-welcome' ).slideUp( 600 ); + $( '#update-messages' ).slideDown( 600 ); + if ( 'true' == wcs_update_script_data.really_old_version ) { + wcs_ajax_update_really_old_version(); + } else if ( 'true' == wcs_update_script_data.upgrade_to_1_5 ) { + wcs_ajax_update_products(); + wcs_ajax_update_hooks(); + } else if ( 'true' == wcs_update_script_data.upgrade_to_2_0 ) { + wcs_ajax_update_subscriptions(); + } else if ( 'true' == wcs_update_script_data.repair_2_0 ) { + wcs_ajax_repair_subscriptions(); + } else { + wcs_ajax_update_complete(); + } + e.preventDefault(); + } ); + function wcs_ajax_update_really_old_version() { + $.ajax( { + url: wcs_update_script_data.ajax_url, + type: 'POST', + data: { + action: 'wcs_upgrade', + upgrade_step: 'really_old_version', + nonce: wcs_update_script_data.upgrade_nonce, + }, + success: function ( results ) { + $( '#update-messages ol' ).append( + $( '
  • ' ).text( results.message ) + ); + wcs_ajax_update_products(); + wcs_ajax_update_hooks(); + }, + error: function ( results, status, errorThrown ) { + wcs_ajax_update_error(); + }, + } ); + } + function wcs_ajax_update_products() { + $.ajax( { + url: wcs_update_script_data.ajax_url, + type: 'POST', + data: { + action: 'wcs_upgrade', + upgrade_step: 'products', + nonce: wcs_update_script_data.upgrade_nonce, + }, + success: function ( results ) { + $( '#update-messages ol' ).append( + $( '
  • ' ).text( results.message ) + ); + }, + error: function ( results, status, errorThrown ) { + wcs_ajax_update_error(); + }, + } ); + } + function wcs_ajax_update_hooks() { + var start_time = new Date(); + $.ajax( { + url: wcs_update_script_data.ajax_url, + type: 'POST', + data: { + action: 'wcs_upgrade', + upgrade_step: 'hooks', + nonce: wcs_update_script_data.upgrade_nonce, + }, + success: function ( results ) { + if ( results.message ) { + var end_time = new Date(), + execution_time = Math.ceil( + ( end_time.getTime() - start_time.getTime() ) / 1000 + ); + $( '#update-messages ol' ).append( + $( '
  • ' ).text( + results.message.replace( + '{execution_time}', + execution_time + ) + ) + ); + } + if ( + undefined == typeof results.upgraded_count || + parseInt( results.upgraded_count ) <= + wcs_update_script_data.hooks_per_request - 1 + ) { + wcs_ajax_update_subscriptions(); + } else { + wcs_ajax_update_hooks(); + } + }, + error: function ( results, status, errorThrown ) { + wcs_ajax_update_error(); + }, + } ); + } + function wcs_ajax_update_subscriptions() { + var start_time = new Date(); + + if ( null === upgrade_start_time ) { + upgrade_start_time = start_time; + } + + $.ajax( { + url: wcs_update_script_data.ajax_url, + type: 'POST', + data: { + action: 'wcs_upgrade', + upgrade_step: 'subscriptions', + nonce: wcs_update_script_data.upgrade_nonce, + }, + success: function ( results ) { + if ( 'success' == results.status ) { + var end_time = new Date(), + execution_time = Math.ceil( + ( end_time.getTime() - start_time.getTime() ) / 1000 + ); + + $( '#update-messages ol' ).append( + $( '
  • ' ).text( + results.message.replace( + '{execution_time}', + execution_time + ) + ) + ); + + wcs_update_script_data.subscription_count -= + results.upgraded_count; + + if ( + 'undefined' === typeof results.upgraded_count || + parseInt( wcs_update_script_data.subscription_count ) <= + 0 + ) { + wcs_ajax_update_complete(); + } else { + wcs_ajax_update_estimated_time( results.time_message ); + wcs_ajax_update_subscriptions(); + } + } else { + wcs_ajax_update_error( results.message ); + } + }, + error: function ( results, status, errorThrown ) { + $( + '
    Error: ' + + results.status + + ' ' + + errorThrown + + '' + ).appendTo( '#update-error p' ); + wcs_ajax_update_error( $( '#update-error p' ).html() ); + }, + } ); + } + function wcs_ajax_repair_subscriptions() { + var start_time = new Date(); + + if ( null === upgrade_start_time ) { + upgrade_start_time = start_time; + } + + $.ajax( { + url: wcs_update_script_data.ajax_url, + type: 'POST', + data: { + action: 'wcs_upgrade', + upgrade_step: 'subscription_dates_repair', + nonce: wcs_update_script_data.upgrade_nonce, + }, + success: function ( results ) { + if ( 'success' == results.status ) { + var end_time = new Date(), + execution_time = Math.ceil( + ( end_time.getTime() - start_time.getTime() ) / 1000 + ); + + $( '#update-messages ol' ).append( + $( '
  • ' ).text( + results.message.replace( + '{execution_time}', + execution_time + ) + ) + ); + + wcs_update_script_data.subscription_count -= + results.repaired_count; + wcs_update_script_data.subscription_count -= + results.unrepaired_count; + + if ( + parseInt( wcs_update_script_data.subscription_count ) <= + 0 + ) { + wcs_ajax_update_complete(); + } else { + wcs_ajax_update_estimated_time( results.time_message ); + wcs_ajax_repair_subscriptions(); + } + } else { + wcs_ajax_update_error( results.message ); + } + }, + error: function ( results, status, errorThrown ) { + $( + '
    Error: ' + + results.status + + ' ' + + errorThrown + + '' + ).appendTo( '#update-error p' ); + wcs_ajax_update_error( $( '#update-error p' ).html() ); + }, + } ); + } + function wcs_ajax_update_complete() { + $( '#update-ajax-loader, #estimated_time' ).slideUp( function () { + $( '#update-complete' ).slideDown(); + } ); + } + function wcs_ajax_update_error( message ) { + message = message || ''; + if ( message.length > 0 ) { + $( '#update-error p' ).html( message ); + } + $( '#update-ajax-loader, #estimated_time' ).slideUp( function () { + $( '#update-error' ).slideDown(); + } ); + } + function wcs_ajax_update_estimated_time( message ) { + var total_updated = + total_subscriptions - wcs_update_script_data.subscription_count, + now = new Date(), + execution_time, + time_per_update, + time_left, + time_left_minutes, + time_left_seconds; + + execution_time = Math.ceil( + ( now.getTime() - upgrade_start_time.getTime() ) / 1000 + ); + time_per_update = execution_time / total_updated; + + time_left = Math.floor( + wcs_update_script_data.subscription_count * time_per_update + ); + time_left_minutes = Math.floor( time_left / 60 ); + time_left_seconds = time_left % 60; + + $( '#estimated_time' ).html( + message.replace( + '{time_left}', + time_left_minutes + ':' + zeropad( time_left_seconds ) + ) + ); + } + function zeropad( number ) { + var pad_char = 0, + pad = new Array( 3 ).join( pad_char ); + return ( pad + number ).slice( -pad.length ); + } +} ); diff --git a/vendor/woocommerce/subscriptions-core/build/index.asset.php b/vendor/woocommerce/subscriptions-core/build/index.asset.php new file mode 100644 index 0000000..e0de4c8 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/build/index.asset.php @@ -0,0 +1 @@ + array('wc-blocks-checkout', 'wc-price-format', 'wc-settings', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => '7855adadf2c3ec0499bc9a7854758556'); \ No newline at end of file diff --git a/vendor/woocommerce/subscriptions-core/build/index.css b/vendor/woocommerce/subscriptions-core/build/index.css new file mode 100644 index 0000000..fdfb15d --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/build/index.css @@ -0,0 +1,2 @@ +.wcs-recurring-totals-panel{position:relative;padding:1em 0 0}.wcs-recurring-totals-panel::after{border-style:solid;border-width:1px 0;bottom:0;content:"";display:block;left:0;opacity:.3;pointer-events:none;position:absolute;right:0;top:0}.wcs-recurring-totals-panel+.wcs-recurring-totals-panel::after{border-top-width:0}.wcs-recurring-totals-panel .wc-block-components-panel .wc-block-components-totals-item{padding-left:0;padding-right:0}.wcs-recurring-totals-panel .wc-block-components-totals-item__label::first-letter{text-transform:capitalize}.wcs-recurring-totals-panel .wcs-recurring-totals-panel__title .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals-panel__title{margin:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__button,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:hover,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:focus{font-size:.875em}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:first-child{margin-top:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:last-child{margin-bottom:0}.wcs-recurring-totals-panel__details .wcs-recurring-totals-panel__details-total .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals__subscription-length{float:right} + diff --git a/vendor/woocommerce/subscriptions-core/build/index.js b/vendor/woocommerce/subscriptions-core/build/index.js new file mode 100644 index 0000000..6267c48 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/build/index.js @@ -0,0 +1,26 @@ +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var c=t[r]={i:r,l:!1,exports:{}};return e[r].call(c.exports,c,c.exports,n),c.l=!0,c.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var c in e)n.d(r,c,function(t){return e[t]}.bind(null,c));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=10)}([function(e,t){e.exports=window.wp.i18n},function(e,t){e.exports=window.wp.element},function(e,t){e.exports=window.wc.blocksCheckout},function(e,t,n){var r=n(7);e.exports=function(e,t){if(null==e)return{};var n,c,i=r(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(c=0;c=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}},function(e,t){e.exports=window.wp.plugins},function(e,t){e.exports=window.wc.priceFormat},function(e,t){e.exports=window.wc.wcSettings},function(e,t){e.exports=function(e,t){if(null==e)return{};var n,r,c={},i=Object.keys(e);for(r=0;r=0||(c[n]=e[n]);return c}},function(e,t,n){},function(e,t,n){},function(e,t,n){"use strict";n.r(t);var r=n(1),c=n(4),i=n(2),o=n(3),s=n.n(o),l=n(0),a=n(5),u=n(6);function p(e){return{day:Object(l._nx)("day","days",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions"),week:Object(l._nx)("week","weeks",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions"),month:Object(l._nx)("month","months",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions"),year:Object(l._nx)("year","years",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions")}}function b(e,t,n){var r=e.billing_interval,c=e.billing_period,i=p(r)[c];switch(t=t.trim(),r){case 1:return"".concat(n," ").concat(t," ").concat(i);default:return Object(l.sprintf)( +/* + * translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/", + * %3$d is the length, %4$s is week, month, year + */ +Object(l.__)("%1$s %2$s %3$d %4$s","woocommerce-subscriptions"),n,t,r,i)}}function m(e){return e.subscriptionLength===e.billingInterval}n(8);var g=Object(u.getSetting)("displayCartPricesIncludingTax",!1),d=function(e){var t=e.currency,n=e.values,c=n.total_discount,o=n.total_discount_tax,s=parseInt(c,10);if(!s)return null;var a=parseInt(o,10),u=g?s+a:s;return Object(r.createElement)(i.TotalsItem,{className:"wc-block-components-totals-discount",currency:t,label:Object(l.__)("Discount","woocommerce-subscriptions"),value:-1*u})},_=function(e){var t=e.values,n=e.currency,c=e.selectedRate,o=e.needsShipping,s=e.calculatedShipping;if(!o||!s)return null;var a=g?parseInt(t.total_shipping,10)+parseInt(t.total_shipping_tax,10):parseInt(t.total_shipping,10);return Object(r.createElement)(i.TotalsItem,{value:a,label:Object(l.__)("Shipping","woocommerce-subscriptions"),currency:n,description:!!c&&Object(l.sprintf)(// translators: %s selected shipping rate (ex: flat rate) +Object(l.__)("via %s","woocommerce-subscriptions"),c)})},f=function(e){var t=e.nextPaymentDate,n=e.subscriptionLength,c=e.billingPeriod,i=e.billingInterval,o=function(e){var t=e.subscriptionLength,n=e.billingPeriod,r=p(t);return Object(l.sprintf)("For %1$d %2$s",t,r[n],"woocommerce-subscriptions")}({subscriptionLength:n,billingPeriod:c}),s=m({subscriptionLength:n,billingInterval:i})?Object(l.sprintf)( +/* Translators: %1$s is a date. */ +Object(l.__)("Due: %1$s","woocommerce-subscriptions"),t):Object(l.sprintf)( +/* Translators: %1$s is a date. */ +Object(l.__)("Starting: %1$s","woocommerce-subscriptions"),t);return Object(r.createElement)("span",null,!!t&&s," ",!!n&&n>=i&&Object(r.createElement)("span",{className:"wcs-recurring-totals__subscription-length"},o))},O=function(e){var t=e.currency,n=e.billingInterval,c=e.billingPeriod,o=e.nextPaymentDate,s=e.subscriptionLength,a=e.totals,u=m({billingInterval:n,subscriptionLength:s})?Object(l.__)("Total","woocommerce-subscriptions"):function(e){var t=e.billingInterval,n=e.billingPeriod;switch(t){case 1:if("day"===n)return Object(l.__)("Daily recurring total","woocommerce-subscriptions");if("week"===n)return Object(l.__)("Weekly recurring total","woocommerce-subscriptions");if("month"===n)return Object(l.__)("Monthly recurring total","woocommerce-subscriptions");if("year"===n)return Object(l.__)("Yearly recurring total","woocommerce-subscriptions");break;case 2:return Object(l.sprintf)( +/* translators: %1$s is week, month, year */ +Object(l.__)("Recurring total every 2nd %1$s","woocommerce-subscriptions"),n);case 3:return Object(l.sprintf)( +/* Translators: %1$s is week, month, year */ +Object(l.__)("Recurring total every 3rd %1$s","woocommerce-subscriptions"),n);default:return Object(l.sprintf)( +/* Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year */ +Object(l.__)("Recurring total every %1$dth %2$s","woocommerce-subscriptions"),t,n)}}({billingInterval:n,billingPeriod:c});return Object(r.createElement)(i.TotalsItem,{className:"wcs-recurring-totals-panel__title",currency:t,label:u,value:a,description:Object(r.createElement)(f,{nextPaymentDate:o,subscriptionLength:s,billingInterval:n,billingPeriod:c})})},j=function(e){var t,n,c,o=e.subscription,s=e.needsShipping,u=e.calculatedShipping,p=o.totals,b=o.billing_interval,m=o.billing_period,f=o.next_payment_date,j=o.subscription_length,w=o.shipping_rates;if(!f)return null;var v=null==w||null===(t=w[0])||void 0===t||null===(n=t.shipping_rates)||void 0===n||null===(c=n.find((function(e){return e.selected})))||void 0===c?void 0:c.name,y=Object(a.getCurrencyFromPriceResponse)(p);return Object(r.createElement)("div",{className:"wcs-recurring-totals-panel"},Object(r.createElement)(O,{billingInterval:b,billingPeriod:m,nextPaymentDate:f,subscriptionLength:j,totals:parseInt(p.total_price,10),currency:y}),Object(r.createElement)(i.Panel,{className:"wcs-recurring-totals-panel__details",initialOpen:!1,title:Object(l.__)("Details","woocommerce-subscriptions")},Object(r.createElement)(i.TotalsWrapper,null,Object(r.createElement)(i.Subtotal,{currency:y,values:p}),Object(r.createElement)(d,{currency:y,values:p})),Object(r.createElement)(i.TotalsWrapper,null,Object(r.createElement)(_,{currency:y,needsShipping:s,calculatedShipping:u,values:p,selectedRate:v})),!g&&Object(r.createElement)(i.TotalsWrapper,null,Object(r.createElement)(i.TotalsTaxes,{currency:y,values:p})),Object(r.createElement)(i.TotalsWrapper,null,Object(r.createElement)(i.TotalsItem,{className:"wcs-recurring-totals-panel__details-total",currency:y,label:Object(l.__)("Total","woocommerce-subscriptions"),value:parseInt(p.total_price,10)}))))},w=function(e){var t=e.extensions,n=e.cart,c=t.subscriptions,i=n.cartNeedsShipping,o=n.cartHasCalculatedShipping;return c&&0!==c.length?c.map((function(e){var t=e.key,n=s()(e,["key"]);return Object(r.createElement)(j,{subscription:n,needsShipping:i,calculatedShipping:o,key:t})})):null},v=function(e){var t=e.extensions,n=e.collapsible,c=e.collapse,i=e.showItems,o=e.noResultsMessage,l=e.renderOption,a=e.components,u=t.subscriptions,p=void 0===u?[]:u,b=a.ShippingRatesControlPackage,m=Object(r.useMemo)((function(){return Object.values(p).map((function(e){return e.shipping_rates})).filter(Boolean).flat()}),[p]),g=Object(r.useMemo)((function(){return 1 Payment methods page should be translatable. PR#125 wcs#4180 wcpay#3974 + += 1.6.4 - 2022-02-10 = +* Fix: When changing the payment method, make sure the subscription total returns $0 when `subscriptions-core` is loaded after the `woocommerce_loaded` action hook. PR#111 wcpay#3768 + += 1.6.3 - 2022-02-07 = +* Fix: Replace uses of is_ajax() with wp_doing_ajax(). PR#108 wcpay#3695 wcs#4296 +* Improve handling of session data. + += 1.6.2 - 2022-01-19 = +* Fix: Prevent fatal error when too few arguments passed to widget_title filter. PR#100 + += 1.6.1 - 2022-01-18 = +* Dev: Update the list of "export-ignore" in `.gitattributes` to include recent developer files. PR#97 +* Dev: Set the composer package type to "wordpress-plugin". PR#96 + += 1.6.0 - 2022-01-17 = +* Fix: When viewing a WCPay Subscription product page, make sure other gateway's express payment buttons aren't shown. PR#87 wcpay#3401 +* Fix: When viewing a WC Product page with a WCPay subscription product in cart, make sure other gateway's express payment buttons are shown. PR#87 wcpay#3401 + += 1.5.0 - 2022-01-14 = +* New: Introduce filter to allow third-parties to specify the minimum recurring amount the payment method can support. Displays a warning to the merchant when creating products below that amount. #PR89 wcpay#3542 + += 1.4.0 - 2022-01-03 = +* Fix: Simple subscription elements on the product edit page not shown/hidden when necessary. PR#80 +* Fix: Prevent fatal errors on the admin subscriptions screen when a subscription fails to load. PR#84 wcpay#3596 wcs#4286 +* Fix: Compatibility issue when loading subscriptions templates. PR#86 wcpay#3606 wcs#4291 + += 1.3.0 - 2021-12-21 = +* Fix: Remove references to the Subscription extension in the tooltips found on the Payment Methods settings table. PR#55 wcpay#3234 +* Fix: Update the Automatic Recurring Payments column on the Payment Methods table to only show which payment methods are supported by Subscriptions Core. PR#55 +* Tweak: Update deprecation message when calling WC_Subscriptions_Coupon::cart_contains_limited_recurring_coupon() to mention the correct replacement function. PR#53 +* Fix: Prevent deprecation warnings when using WooCommerce Blocks. PR#54 +* Tweak: Update recurring payments copy on payment gateways page. +* Fix: Incorrect text when filtering subscriptions to no results. +* Changed: Subscription products must have a recurring amount greater than $0. PR#56 wcpay#3309 + += 1.2.0 - 2021-11-23 = +* Fix: Update tooltip wording when deleting product variation. PR#46 +* Fix: Don't show an admin error notice when a store downgrades to a previous minor version of Subscriptions. WCS#4271 + += 1.1.0 - 2021-11-12 = +* Fix: Add consistent margins to the recurring taxes totals row on the Checkout and Cart block. PR#39 +* Fix: Fatal error due to order with no created date in order row template. PR#40 +* Fix: Fatal error on the customer payment page for renewal orders with deleted products. PR#42 +* Fix: Misleading order note on payment method change. PR#41 + += 1.0.3 - 2021-10-29 = +* Fix: Errors when attempting to get the plugin version during PayPal requests. PR#27 + += 1.0.2 - 2021-10-29 = +* Fix: PHP 7.2 compatibility - remove trailing commas from function args. PR #23 + += 1.0.1 - 2021-10-22 = +* Fix: Don't show a downgrade notice when activating the WC Subscriptions extension after installing WCS Core. PR#7 +* Fix: Correctly show the available payment methods when paying for a subscription renewal order. PR#9 +* Fix: Don't show the WC Subscriptions extension welcome/installation message after installing WCS Core. PR#11 +* Fix: Remove the "Welcome to Subscriptions" notice that is displayed upon upgrading from previous minor versions. PR#14 +* Fix: Don't display a "Welcome to Subscriptions 2.1" for stores that have upgraded from really old version of Subscriptions. PR#16 +* Fix: Errors during the upgrade process for stores that are upgrading from very old versions of Subscriptions (1.5.0). PR#16 +* Fix: Show subscription billing information (recurring cart totals, sign up fees etc) on the WooCommerce Checkout block. PR#18 + += 1.0.0 - 2021-09-22 = +* New: Subscriptions Core first release diff --git a/includes/abstracts/abstract-wcs-background-repairer.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-repairer.php similarity index 100% rename from includes/abstracts/abstract-wcs-background-repairer.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-repairer.php diff --git a/includes/abstracts/abstract-wcs-background-updater.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-updater.php similarity index 95% rename from includes/abstracts/abstract-wcs-background-updater.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-updater.php index a251cf7..c0ec55b 100644 --- a/includes/abstracts/abstract-wcs-background-updater.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-updater.php @@ -125,7 +125,8 @@ abstract class WCS_Background_Updater { * Schedule the instance's hook to run in $this->time_limit seconds, if it's not already scheduled. */ protected function schedule_background_update() { - if ( false === as_next_scheduled_action( $this->scheduled_hook ) ) { + // A timestamp is returned if there's a pending action already scheduled. Otherwise true if its running or false if one doesn't exist. + if ( ! is_numeric( as_next_scheduled_action( $this->scheduled_hook ) ) ) { as_schedule_single_action( gmdate( 'U' ) + $this->time_limit, $this->scheduled_hook ); } } diff --git a/includes/abstracts/abstract-wcs-background-upgrader.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-upgrader.php similarity index 100% rename from includes/abstracts/abstract-wcs-background-upgrader.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-background-upgrader.php diff --git a/includes/abstracts/abstract-wcs-cache-manager.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-cache-manager.php similarity index 97% rename from includes/abstracts/abstract-wcs-cache-manager.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-cache-manager.php index c804404..c5fa842 100644 --- a/includes/abstracts/abstract-wcs-cache-manager.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-cache-manager.php @@ -17,7 +17,7 @@ abstract class WCS_Cache_Manager { * Modeled after WP_Session_Tokens */ $manager = apply_filters( 'wcs_cache_manager_class', 'WCS_Cached_Data_Manager' ); - return new $manager; + return new $manager(); } /** diff --git a/includes/abstracts/abstract-wcs-customer-store.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-customer-store.php similarity index 94% rename from includes/abstracts/abstract-wcs-customer-store.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-customer-store.php index 7d26e3e..12caee9 100644 --- a/includes/abstracts/abstract-wcs-customer-store.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-customer-store.php @@ -43,7 +43,7 @@ abstract class WCS_Customer_Store { wcs_doing_it_wrong( __METHOD__, 'This method was called before the "plugins_loaded" hook. It applies a filter to the customer data store instantiated. For that to work, it should first be called after all plugins are loaded.', '2.3.0' ); } - $class = apply_filters( 'wcs_customer_store_class', 'WCS_Customer_Store_Cached_CPT' ); + $class = apply_filters( 'wcs_customer_store_class', 'WCS_Customer_Store_Cached_CPT' ); self::$instance = new $class(); self::$instance->init(); } diff --git a/includes/abstracts/abstract-wcs-debug-tool-cache-updater.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-debug-tool-cache-updater.php similarity index 100% rename from includes/abstracts/abstract-wcs-debug-tool-cache-updater.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-debug-tool-cache-updater.php diff --git a/includes/abstracts/abstract-wcs-debug-tool.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-debug-tool.php similarity index 100% rename from includes/abstracts/abstract-wcs-debug-tool.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-debug-tool.php diff --git a/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-deprecated-functions-handler.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-deprecated-functions-handler.php new file mode 100644 index 0000000..cb11a9d --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-deprecated-functions-handler.php @@ -0,0 +1,121 @@ + array( + * 'replacement' => string|array The replacement function to call. + * 'version' => string The version the function was deprecated. + * )... + * + * @var array[] + */ + protected $deprecated_functions = array(); + + /** + * Determines if a function is deprecated and handled by this class. + * + * @since 4.0.0 + * + * @param string $function The function to check. + * @return bool + */ + public function is_deprecated( $function ) { + return isset( $this->deprecated_functions[ $function ] ); + } + + /** + * Determines if there's a replacement function to call. + * + * @since 4.0.0 + * + * @param string $function The deprecated function to check if there's a replacement for. + * @return bool + */ + public function has_replacement( $function ) { + return isset( $this->deprecated_functions[ $function ]['replacement'] ); + } + + /** + * Calls the replacement function if one exists. + * + * @since 4.0.0 + * + * @param string $function The deprecated function. + * @param array $arguments The deprecated function arguments. + * + * @return mixed Returns what ever the replacement function returns. + */ + public function call_replacement( $function, $arguments = array() ) { + if ( $this->is_deprecated( $function ) && $this->has_replacement( $function ) ) { + $replacement = $this->deprecated_functions[ $function ]['replacement']; + + // Handle replacements which are handled internally. + if ( is_array( $replacement ) ) { + if ( is_array( $replacement[0] ) ) { + $instance = call_user_func( $replacement[0] ); + + return call_user_func_array( array( $instance, $replacement[1] ), $arguments ); + } elseif ( get_class( $this ) === $replacement[0] ) { + return $this->{$replacement[1]}( ...$arguments ); + } + } else { + return call_user_func_array( $replacement, $arguments ); + } + } + } + + /** + * Triggers the deprecated notice. + * + * @since 4.0.0 + * @param string $function The deprecated function. + */ + public function trigger_notice( $function ) { + + if ( $this->is_deprecated( $function ) ) { + $version_deprecated = $this->deprecated_functions[ $function ]['version']; + $deprecated_function = empty( $this->class ) ? $function : "{$this->class}::{$function}"; + $replacement_function = null; + + // Format the replacement function to be outputted. + if ( $this->has_replacement( $function ) ) { + $replacement_function = $this->deprecated_functions[ $function ]['replacement']; + + if ( is_array( $replacement_function ) ) { + + if ( is_array( $replacement_function[0] ) ) { + $replacement_function[0] = implode( '::', $replacement_function[0] ) . '()'; + $replacement_function = implode( '->', $replacement_function ) . '()'; + } elseif ( get_class( $this ) === $replacement_function[0] ) { + // Replacement functions which point back to the handler class, aren't legitimate replacements so treat them as having no replacements. + $replacement_function = null; + } else { + $replacement_function = implode( '::', $replacement_function ) . '()'; + } + } + } + + wcs_deprecated_function( $deprecated_function, $version_deprecated, $replacement_function ); + } + } +} diff --git a/includes/abstracts/abstract-wcs-dynamic-hook-deprecator.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-dynamic-hook-deprecator.php similarity index 100% rename from includes/abstracts/abstract-wcs-dynamic-hook-deprecator.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-dynamic-hook-deprecator.php diff --git a/includes/abstracts/abstract-wcs-hook-deprecator.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-hook-deprecator.php similarity index 95% rename from includes/abstracts/abstract-wcs-hook-deprecator.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-hook-deprecator.php index bf562e7..6d8fc53 100644 --- a/includes/abstracts/abstract-wcs-hook-deprecator.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-hook-deprecator.php @@ -121,8 +121,8 @@ abstract class WCS_Hook_Deprecator { * @since 2.0 */ protected static function get_product_id( $subscription ) { - $order_items = $subscription->get_items(); - $product_id = ( empty( $order_items ) ) ? 0 : WC_Subscriptions_Order::get_items_product_id( reset( $order_items ) ); + $order_items = $subscription->get_items(); + $product_id = ( empty( $order_items ) ) ? 0 : WC_Subscriptions_Order::get_items_product_id( reset( $order_items ) ); return $product_id; } } diff --git a/includes/abstracts/abstract-wcs-migrator.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-migrator.php similarity index 100% rename from includes/abstracts/abstract-wcs-migrator.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-migrator.php diff --git a/includes/abstracts/abstract-wcs-related-order-store.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php similarity index 98% rename from includes/abstracts/abstract-wcs-related-order-store.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php index 14e4251..1f0d2f8 100644 --- a/includes/abstracts/abstract-wcs-related-order-store.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php @@ -68,7 +68,7 @@ abstract class WCS_Related_Order_Store { self::$relation_type_keys = array_fill_keys( self::$relation_types, true ); - $class = apply_filters( 'wcs_related_order_store_class', 'WCS_Related_Order_Store_Cached_CPT' ); + $class = apply_filters( 'wcs_related_order_store_class', 'WCS_Related_Order_Store_Cached_CPT' ); self::$instance = new $class(); self::$instance->init(); } diff --git a/includes/abstracts/abstract-wcs-scheduler.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-scheduler.php similarity index 100% rename from includes/abstracts/abstract-wcs-scheduler.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-scheduler.php diff --git a/includes/abstracts/abstract-wcs-table-maker.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-table-maker.php similarity index 98% rename from includes/abstracts/abstract-wcs-table-maker.php rename to vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-table-maker.php index 7925530..6b0afa5 100644 --- a/includes/abstracts/abstract-wcs-table-maker.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-table-maker.php @@ -104,7 +104,7 @@ abstract class WCS_Table_Maker { * @param string $table The name of the table to update */ private function update_table( $table ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $definition = $this->get_table_definition( $table ); if ( $definition ) { $updated = dbDelta( $definition ); diff --git a/includes/admin/class-wc-subscriptions-admin.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php similarity index 82% rename from includes/admin/class-wc-subscriptions-admin.php rename to vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php index 237fe94..3c42b6f 100644 --- a/includes/admin/class-wc-subscriptions-admin.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php @@ -71,7 +71,11 @@ class WC_Subscriptions_Admin { add_action( 'woocommerce_page_wc-status', __CLASS__ . '::clear_subscriptions_transients' ); // Add subscription shipping options on edit product page - add_action( 'woocommerce_product_options_shipping', __CLASS__ . '::subscription_shipping_fields' ); + if ( wcs_is_woocommerce_pre( '6.0' ) ) { + add_action( 'woocommerce_product_options_shipping', __CLASS__ . '::subscription_shipping_fields' ); + } else { + add_action( 'woocommerce_product_options_shipping_product_data', __CLASS__ . '::subscription_shipping_fields' ); + } // And also on the variations section add_action( 'woocommerce_product_after_variable_attributes', __CLASS__ . '::variable_subscription_pricing_fields', 10, 3 ); @@ -142,6 +146,12 @@ class WC_Subscriptions_Admin { // Validate the product type change before other product changes are saved. add_action( 'woocommerce_process_product_meta', array( __CLASS__, 'validate_product_type_change' ), 5 ); + + // Allow admin to enable account creation specifically for subscription purchases. + add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_registration_for_subscription_purchases_setting' ), 10, 1 ); + + // Prevent variations from being deleted if switching from a variable product type to a variable product type. + add_filter( 'woocommerce_delete_variations_on_product_type_change', array( __CLASS__, 'maybe_keep_variations' ), 10, 4 ); } /** @@ -380,7 +390,13 @@ class WC_Subscriptions_Admin { public static function subscription_shipping_fields() { global $post; - echo ''; + $needs_html_fix = 'woocommerce_product_options_shipping' === current_filter(); + + // Old hook is nested and requires invalid html markup to be compatible with other plugins. + if ( $needs_html_fix ) { + echo ''; + } + echo ''; + } + } /** @@ -428,7 +448,7 @@ class WC_Subscriptions_Admin { $billing_period = 'month'; } - include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/html-variation-price.php' ); + include( WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/html-variation-price.php' ) ); wp_nonce_field( 'wcs_subscription_variations', '_wcsnonce_save_variations', false ); @@ -464,7 +484,7 @@ class WC_Subscriptions_Admin { */ public static function save_subscription_meta( $post_id ) { - if ( empty( $_POST['_wcsnonce'] ) || ! wp_verify_nonce( $_POST['_wcsnonce'], 'wcs_subscription_meta' ) || false === self::is_subscription_product_save_request( $post_id, apply_filters( 'woocommerce_subscription_product_types', array( WC_Subscriptions::$name ) ) ) ) { + if ( empty( $_POST['_wcsnonce'] ) || ! wp_verify_nonce( $_POST['_wcsnonce'], 'wcs_subscription_meta' ) || false === self::is_subscription_product_save_request( $post_id, apply_filters( 'woocommerce_subscription_product_types', array( WC_Subscriptions_Core_Plugin::instance()->get_product_type_name() ) ) ) ) { return; } @@ -687,7 +707,7 @@ class WC_Subscriptions_Admin { $_POST['variable_regular_price'] = isset( $_POST['variable_subscription_price'] ) ? $_POST['variable_subscription_price'] : 0; // Sync the min variation price - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $variable_subscription = wc_get_product( $post_id ); $variable_subscription->variable_product_sync(); } else { @@ -810,7 +830,6 @@ class WC_Subscriptions_Admin { $screen = get_current_screen(); $is_woocommerce_screen = in_array( $screen->id, array( 'product', 'edit-shop_order', 'shop_order', 'edit-shop_subscription', 'shop_subscription', 'users', 'woocommerce_page_wc-settings' ) ); - $is_activation_screen = (bool) get_transient( WC_Subscriptions::$activation_transient ); if ( $is_woocommerce_screen ) { @@ -825,18 +844,23 @@ class WC_Subscriptions_Admin { $dependencies[] = 'wc-admin-variation-meta-boxes'; $script_params = array( - 'productType' => WC_Subscriptions::$name, - 'trialPeriodSingular' => wcs_get_available_time_periods(), - 'trialPeriodPlurals' => wcs_get_available_time_periods( 'plural' ), - 'subscriptionLengths' => wcs_get_subscription_ranges(), - 'trialTooLongMessages' => self::get_trial_period_validation_message( 'separate' ), - 'bulkEditPeriodMessage' => __( 'Enter the new period, either day, week, month or year:', 'woocommerce-subscriptions' ), - 'bulkEditLengthMessage' => __( 'Enter a new length (e.g. 5):', 'woocommerce-subscriptions' ), - 'bulkEditIntervalhMessage' => __( 'Enter a new interval as a single number (e.g. to charge every 2nd month, enter 2):', 'woocommerce-subscriptions' ), - 'bulkDeleteOptionLabel' => __( 'Delete all variations without a subscription', 'woocommerce-subscriptions' ), - 'oneTimeShippingCheckNonce' => wp_create_nonce( 'one_time_shipping' ), - 'productHasSubscriptions' => ! wcs_is_large_site() && wcs_get_subscriptions_for_product( $post->ID, 'ids', array( 'limit' => 1 ) ) ? 'yes' : 'no', - 'productTypeWarning' => self::get_change_product_type_warning(), + 'productType' => WC_Subscriptions_Core_Plugin::instance()->get_product_type_name(), + 'trialPeriodSingular' => wcs_get_available_time_periods(), + 'trialPeriodPlurals' => wcs_get_available_time_periods( 'plural' ), + 'subscriptionLengths' => wcs_get_subscription_ranges(), + 'trialTooLongMessages' => self::get_trial_period_validation_message( 'separate' ), + 'bulkEditPeriodMessage' => __( 'Enter the new period, either day, week, month or year:', 'woocommerce-subscriptions' ), + 'bulkEditLengthMessage' => __( 'Enter a new length (e.g. 5):', 'woocommerce-subscriptions' ), + 'bulkEditIntervalhMessage' => __( 'Enter a new interval as a single number (e.g. to charge every 2nd month, enter 2):', 'woocommerce-subscriptions' ), + 'bulkDeleteOptionLabel' => __( 'Delete all variations without a subscription', 'woocommerce-subscriptions' ), + 'oneTimeShippingCheckNonce' => wp_create_nonce( 'one_time_shipping' ), + 'productHasSubscriptions' => ! wcs_is_large_site() && wcs_get_subscriptions_for_product( $post->ID, 'ids', array( 'limit' => 1 ) ) ? 'yes' : 'no', + 'productTypeWarning' => self::get_change_product_type_warning(), + 'isLargeSite' => wcs_is_large_site(), + 'nonce' => wp_create_nonce( 'wc_subscriptions_admin' ), + 'variationDeleteErrorMessage' => __( 'An error occurred determining if that variation can be deleted. Please try again.', 'woocommerce-subscriptions' ), + 'variationDeleteFailMessage' => __( 'That variation can not be removed because it is associated with active subscriptions. To remove this variation, please cancel and delete the subscriptions for it.', 'woocommerce-subscriptions' ), + ); } elseif ( 'edit-shop_order' == $screen->id ) { $script_params = array( @@ -847,7 +871,7 @@ class WC_Subscriptions_Admin { $dependencies[] = $woocommerce_admin_script_handle; $dependencies[] = 'wc-admin-order-meta-boxes'; - if ( WC_Subscriptions::is_woocommerce_pre( '2.6' ) ) { + if ( wcs_is_woocommerce_pre( '2.6' ) ) { $dependencies[] = 'wc-admin-order-meta-boxes-modal'; } @@ -871,9 +895,9 @@ class WC_Subscriptions_Admin { $script_params['ajaxLoaderImage'] = WC()->plugin_url() . '/assets/images/ajax-loader.gif'; $script_params['ajaxUrl'] = admin_url( 'admin-ajax.php' ); - $script_params['isWCPre24'] = var_export( WC_Subscriptions::is_woocommerce_pre( '2.4' ), true ); + $script_params['isWCPre24'] = var_export( wcs_is_woocommerce_pre( '2.4' ), true ); - wp_enqueue_script( 'woocommerce_subscriptions_admin', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/admin.js', $dependencies, filemtime( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/admin.js' ) ); + wp_enqueue_script( 'woocommerce_subscriptions_admin', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/admin.js' ), $dependencies, filemtime( WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'assets/js/admin/admin.js' ) ) ); wp_localize_script( 'woocommerce_subscriptions_admin', 'WCSubscriptions', apply_filters( 'woocommerce_subscriptions_admin_script_parameters', $script_params ) ); // Maybe add the pointers for first timers @@ -888,7 +912,7 @@ class WC_Subscriptions_Admin { 'pricePointerContent' => sprintf( _x( '%1$sSet a Price%2$s%3$sSubscription prices are a little different to other product prices. For a subscription, you can set a billing period, length, sign-up fee and free trial.%4$s', 'used in admin pointer script params in javascript as price pointer content', 'woocommerce-subscriptions' ), '

    ', '

    ', '

    ', '

    ' ), ); - wp_enqueue_script( 'woocommerce_subscriptions_admin_pointers', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/admin/admin-pointers.js', $dependencies, WC_Subscriptions::$version ); + wp_enqueue_script( 'woocommerce_subscriptions_admin_pointers', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/admin-pointers.js' ), $dependencies, WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() ); wp_localize_script( 'woocommerce_subscriptions_admin_pointers', 'WCSPointers', apply_filters( 'woocommerce_subscriptions_admin_pointer_script_parameters', $pointer_script_params ) ); @@ -896,38 +920,13 @@ class WC_Subscriptions_Admin { } } - // Maybe add the admin notice - if ( $is_activation_screen ) { - - $woocommerce_plugin_dir_file = self::get_woocommerce_plugin_dir_file(); - - // check if subscription products exist in the store - $subscription_product = wc_get_products( - array( - 'type' => array( 'subscription', 'variable-subscription' ), - 'limit' => 1, - 'return' => 'ids', - ) - ); - - if ( ! empty( $woocommerce_plugin_dir_file ) && 0 == count( $subscription_product ) ) { - - wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', $woocommerce_plugin_dir_file ), array(), WC_Subscriptions::$version ); - - if ( ! isset( $_GET['page'] ) || 'wcs-about' != $_GET['page'] ) { - add_action( 'admin_notices', __CLASS__ . '::admin_installed_notice' ); - } - } - delete_transient( WC_Subscriptions::$activation_transient ); + if ( $is_woocommerce_screen || 'edit-product' == $screen->id || ( isset( $_GET['page'], $_GET['tab'] ) && 'wc-reports' === $_GET['page'] && 'subscriptions' === $_GET['tab'] ) ) { + wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() ); + wp_enqueue_style( 'woocommerce_subscriptions_admin', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/css/admin.css' ), array( 'woocommerce_admin_styles' ), WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() ); } - if ( $is_woocommerce_screen || $is_activation_screen || 'edit-product' == $screen->id || ( isset( $_GET['page'], $_GET['tab'] ) && 'wc-reports' === $_GET['page'] && 'subscriptions' === $_GET['tab'] ) ) { - wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), WC_Subscriptions::$version ); - wp_enqueue_style( 'woocommerce_subscriptions_admin', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/css/admin.css', array( 'woocommerce_admin_styles' ), WC_Subscriptions::$version ); - } - - if ( in_array( $screen->id, array( 'shop_order', 'edit-shop_subscription', 'shop_subscription' ) ) && WC_Subscriptions::is_woocommerce_pre( '3.3' ) ) { - wp_enqueue_style( 'wc_subscriptions_statuses_admin', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/css/admin-order-statuses.css', array( 'woocommerce_admin_styles' ), WC_Subscriptions::$version ); + if ( in_array( $screen->id, array( 'shop_order', 'edit-shop_subscription', 'shop_subscription' ) ) && wcs_is_woocommerce_pre( '3.3' ) ) { + wp_enqueue_style( 'wc_subscriptions_statuses_admin', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/css/admin-order-statuses.css' ), array( 'woocommerce_admin_styles' ), WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() ); } } @@ -1178,7 +1177,22 @@ class WC_Subscriptions_Admin { add_option( $setting['id'], $setting['default'] ); } } + } + /** + * Deteremines if the subscriptions settings have been setup. + * + * @since 4.0.0 + * @return bool Whether any subscription settings exist. + */ + public static function has_settings() { + foreach ( self::get_settings() as $setting ) { + if ( get_option( $setting['id'], false ) !== false ) { + return true; + } + } + + return false; } /** @@ -1188,126 +1202,9 @@ class WC_Subscriptions_Admin { * @since 1.0 */ public static function get_settings() { - if ( ! function_exists( 'get_editable_roles' ) ) { - require_once( ABSPATH . 'wp-admin/includes/user.php' ); - } - - $roles = get_editable_roles(); - - foreach ( $roles as $role => $details ) { - $roles_options[ $role ] = translate_user_role( $details['name'] ); - } return apply_filters( 'woocommerce_subscription_settings', array( - array( - 'name' => __( 'Button Text', 'woocommerce-subscriptions' ), - 'type' => 'title', - 'desc' => '', - 'id' => self::$option_prefix . '_button_text', - ), - - array( - 'name' => __( 'Add to Cart Button Text', 'woocommerce-subscriptions' ), - 'desc' => __( 'A product displays a button with the text "Add to cart". By default, a subscription changes this to "Sign up now". You can customise the button text for subscriptions here.', 'woocommerce-subscriptions' ), - 'tip' => '', - 'id' => self::$option_prefix . '_add_to_cart_button_text', - 'css' => 'min-width:150px;', - 'default' => __( 'Sign up now', 'woocommerce-subscriptions' ), - 'type' => 'text', - 'desc_tip' => true, - 'placeholder' => __( 'Sign up now', 'woocommerce-subscriptions' ), - ), - - array( - 'name' => __( 'Place Order Button Text', 'woocommerce-subscriptions' ), - 'desc' => __( 'Use this field to customise the text displayed on the checkout button when an order contains a subscription. Normally the checkout submission button displays "Place order". When the cart contains a subscription, this is changed to "Sign up now".', 'woocommerce-subscriptions' ), - 'tip' => '', - 'id' => self::$option_prefix . '_order_button_text', - 'css' => 'min-width:150px;', - 'default' => __( 'Sign up now', 'woocommerce-subscriptions' ), - 'type' => 'text', - 'desc_tip' => true, - 'placeholder' => __( 'Sign up now', 'woocommerce-subscriptions' ), - ), - - array( - 'type' => 'sectionend', - 'id' => self::$option_prefix . '_button_text', - ), - - array( - 'name' => __( 'Roles', 'woocommerce-subscriptions' ), - 'type' => 'title', - // translators: placeholders are tags - 'desc' => sprintf( __( 'Choose the default roles to assign to active and inactive subscribers. For record keeping purposes, a user account must be created for subscribers. Users with the %1$sadministrator%2$s role, such as yourself, will never be allocated these roles to prevent locking out administrators.', 'woocommerce-subscriptions' ), '', '' ), - 'id' => self::$option_prefix . '_role_options', - ), - - array( - 'name' => __( 'Subscriber Default Role', 'woocommerce-subscriptions' ), - 'desc' => __( 'When a subscription is activated, either manually or after a successful purchase, new users will be assigned this role.', 'woocommerce-subscriptions' ), - 'tip' => '', - 'id' => self::$option_prefix . '_subscriber_role', - 'css' => 'min-width:150px;', - 'default' => 'subscriber', - 'type' => 'select', - 'options' => $roles_options, - 'desc_tip' => true, - ), - - array( - 'name' => __( 'Inactive Subscriber Role', 'woocommerce-subscriptions' ), - 'desc' => __( 'If a subscriber\'s subscription is manually cancelled or expires, she will be assigned this role.', 'woocommerce-subscriptions' ), - 'tip' => '', - 'id' => self::$option_prefix . '_cancelled_role', - 'css' => 'min-width:150px;', - 'default' => 'customer', - 'type' => 'select', - 'options' => $roles_options, - 'desc_tip' => true, - ), - - array( - 'type' => 'sectionend', - 'id' => self::$option_prefix . '_role_options', - ), - - array( - 'name' => _x( 'Renewals', 'option section heading', 'woocommerce-subscriptions' ), - 'type' => 'title', - 'desc' => '', - 'id' => self::$option_prefix . '_renewal_options', - ), - - array( - 'name' => __( 'Manual Renewal Payments', 'woocommerce-subscriptions' ), - 'desc' => __( 'Accept Manual Renewals', 'woocommerce-subscriptions' ), - 'id' => self::$option_prefix . '_accept_manual_renewals', - 'default' => 'no', - 'type' => 'checkbox', - // translators: placeholders are opening and closing link tags - 'desc_tip' => sprintf( __( 'With manual renewals, a customer\'s subscription is put on-hold until they login and pay to renew it. %1$sLearn more%2$s.', 'woocommerce-subscriptions' ), '
    ', '' ), - 'checkboxgroup' => 'start', - 'show_if_checked' => 'option', - ), - - array( - 'desc' => __( 'Turn off Automatic Payments', 'woocommerce-subscriptions' ), - 'id' => self::$option_prefix . '_turn_off_automatic_payments', - 'default' => 'no', - 'type' => 'checkbox', - // translators: placeholders are opening and closing link tags - 'desc_tip' => sprintf( __( 'If you don\'t want new subscription purchases to automatically charge renewal payments, you can turn off automatic payments. Existing automatic subscriptions will continue to charge customers automatically. %1$sLearn more%2$s.', 'woocommerce-subscriptions' ), '', '' ), - 'checkboxgroup' => 'end', - 'show_if_checked' => 'yes', - ), - - array( - 'type' => 'sectionend', - 'id' => self::$option_prefix . '_renewal_options', - ), - array( 'name' => _x( 'Miscellaneous', 'options section heading', 'woocommerce-subscriptions' ), 'type' => 'title', @@ -1315,17 +1212,6 @@ class WC_Subscriptions_Admin { 'id' => self::$option_prefix . '_miscellaneous', ), - array( - 'name' => __( 'Customer Suspensions', 'woocommerce-subscriptions' ), - 'desc' => _x( 'suspensions per billing period.', 'there\'s a number immediately in front of this text', 'woocommerce-subscriptions' ), - 'id' => self::$option_prefix . '_max_customer_suspensions', - 'css' => 'min-width:50px;', - 'default' => 0, - 'type' => 'select', - 'options' => apply_filters( 'woocommerce_subscriptions_max_customer_suspension_range', array_merge( range( 0, 12 ), array( 'unlimited' => 'Unlimited' ) ) ), - 'desc_tip' => __( 'Set a maximum number of times a customer can suspend their account for each billing period. For example, for a value of 3 and a subscription billed yearly, if the customer has suspended their account 3 times, they will not be presented with the option to suspend their account until the next year. Store managers will always be able to suspend an active subscription. Set this to 0 to turn off the customer suspension feature completely.', 'woocommerce-subscriptions' ), - ), - array( 'name' => __( 'Mixed Checkout', 'woocommerce-subscriptions' ), 'desc' => __( 'Allow multiple subscriptions and products to be purchased simultaneously.', 'woocommerce-subscriptions' ), @@ -1335,25 +1221,6 @@ class WC_Subscriptions_Admin { 'desc_tip' => __( 'Allow a subscription product to be purchased with other products and subscriptions in the same transaction.', 'woocommerce-subscriptions' ), ), - array( - 'name' => __( '$0 Initial Checkout', 'woocommerce-subscriptions' ), - 'desc' => __( 'Allow $0 initial checkout without a payment method.', 'woocommerce-subscriptions' ), - 'id' => self::$option_prefix . '_zero_initial_payment_requires_payment', - 'default' => 'no', - 'type' => 'checkbox', - 'desc_tip' => __( 'Allow a subscription product with a $0 initial payment to be purchased without providing a payment method. The customer will be required to provide a payment method at the end of the initial period to keep the subscription active.', 'woocommerce-subscriptions' ), - ), - - array( - 'name' => __( 'Drip Downloadable Content', 'woocommerce-subscriptions' ), - 'desc' => __( 'Enable dripping for downloadable content on subscription products.', 'woocommerce-subscriptions' ), - 'id' => self::$option_prefix . '_drip_downloadable_content_on_renewal', - 'default' => 'no', - 'type' => 'checkbox', - // translators: %s is a line break. - 'desc_tip' => sprintf( __( 'Enabling this grants access to new downloadable files added to a product only after the next renewal is processed.%sBy default, access to new downloadable files added to a product is granted immediately to any customer that has an active subscription with that product.', 'woocommerce-subscriptions' ), '
    ' ), - ), - array( 'type' => 'sectionend', 'id' => self::$option_prefix . '_miscellaneous', @@ -1378,48 +1245,6 @@ class WC_Subscriptions_Admin { } } - /** - * Outputs a welcome message. Called when the Subscriptions extension is activated. - * - * @since 1.0 - */ - public static function admin_installed_notice() { - ?> -
    -
    -

    - tags, $3-$4: opening and closing tags - __( - '%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou\'re ready to start selling subscriptions!%4$s', - 'woocommerce-subscriptions' - ), - '', - '', - '', - '' - ), - array( - 'strong' => true, - 'em' => true, - ) - ); - ?> -

    - -

    - - - - -

    -
    -
    - 0 && true === self::$found_related_orders ) { - $initial_order = new WC_Order( absint( $_GET[ $query_arg ] ) ); + $initial_order = wc_get_order( absint( $_GET[ $query_arg ] ) ); if ( version_compare( $wp_version, '4.2', '<' ) ) { echo '

    '; @@ -1702,7 +1527,7 @@ class WC_Subscriptions_Admin { 'user_id' => $attributes['user_id'], ), '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' + WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); return ob_get_clean(); @@ -1727,8 +1552,8 @@ class WC_Subscriptions_Admin { $debug_data['wcs_staging'] = array( 'name' => _x( 'Subscriptions Mode', 'Live or Staging, Label on WooCommerce -> System Status page', 'woocommerce-subscriptions' ), - 'note' => '' . ( ( WC_Subscriptions::is_duplicate_site() ) ? _x( 'Staging', 'refers to staging site', 'woocommerce-subscriptions' ) : _x( 'Live', 'refers to live site', 'woocommerce-subscriptions' ) ) . '', - 'success' => ( WC_Subscriptions::is_duplicate_site() ) ? 0 : 1, + 'note' => '' . ( ( WCS_Staging::is_duplicate_site() ) ? _x( 'Staging', 'refers to staging site', 'woocommerce-subscriptions' ) : _x( 'Live', 'refers to live site', 'woocommerce-subscriptions' ) ) . '', + 'success' => ( WCS_Staging::is_duplicate_site() ) ? 0 : 1, ); return $debug_data; @@ -1786,9 +1611,11 @@ class WC_Subscriptions_Admin { * @since 2.5.3 */ public static function payment_gateways_renewal_support( $gateway ) { + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); + echo ''; - if ( ( is_array( $gateway->supports ) && in_array( 'subscriptions', $gateway->supports ) ) || $gateway->id == 'paypal' ) { - $status_html = '' . esc_html__( 'Yes', 'woocommerce-subscriptions' ) . ''; + if ( $payment_gateways_handler::gateway_supports_subscriptions( $gateway ) ) { + $status_html = '' . esc_html__( 'Yes', 'woocommerce-subscriptions' ) . ''; } else { $status_html = '-'; } @@ -1898,41 +1725,38 @@ class WC_Subscriptions_Admin { } /** - * Add recurring payment gateway information after the Settings->Checkout->Payment Gateways table. - * This includes links to find additional gateways, information about manual renewals - * and a warning if no payment gateway which supports automatic recurring payments is enabled/setup correctly. + * Add recurring payment gateway information after the Settings->Payments->Payment Methods table. + * This includes information about manual renewals and a warning if no payment gateway which supports automatic recurring payments is enabled/setup correctly. * * @since 2.1 */ public static function add_recurring_payment_gateway_information( $settings ) { $available_gateways_description = ''; + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); - if ( ! WC_Subscriptions_Payment_Gateways::one_gateway_supports( 'subscriptions' ) ) { + if ( ! $payment_gateways_handler::one_gateway_supports( 'subscriptions' ) ) { // translators: $1-2: opening and closing tags of a link that takes to Woo marketplace / Stripe product page $available_gateways_description = sprintf( __( 'No payment gateways capable of processing automatic subscription payments are enabled. If you would like to process automatic payments, we recommend the %1$sfree Stripe extension%2$s.', 'woocommerce-subscriptions' ), '', '' ); } - $recurring_payment_settings = array( + $recurring_payment_settings = apply_filters( + 'woocommerce_subscriptions_admin_recurring_payment_information', array( - 'name' => __( 'Recurring Payments', 'woocommerce-subscriptions' ), - 'desc' => $available_gateways_description, - 'id' => WC_Subscriptions_Admin::$option_prefix . '_payment_gateways_available', - 'type' => 'informational', - ), + array( + 'name' => __( 'Recurring Payments', 'woocommerce-subscriptions' ), + 'desc' => $available_gateways_description, + 'id' => WC_Subscriptions_Admin::$option_prefix . '_payment_gateways_available', + 'type' => 'informational', + ), - array( - // translators: placeholders are opening and closing link tags - 'desc' => sprintf( __( 'Payment gateways which don\'t support automatic recurring payments can be used to process %1$smanual subscription renewal payments%2$s.', 'woocommerce-subscriptions' ), '', '' ), - 'id' => WC_Subscriptions_Admin::$option_prefix . '_payment_gateways_additional', - 'type' => 'informational', - ), - - array( - // translators: $1-$2: opening and closing tags. Link to documents->payment gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions shop page - 'desc' => sprintf( __( 'Find new gateways that %1$ssupport automatic subscription payments%2$s in the official %3$sWooCommerce Marketplace%4$s.', 'woocommerce-subscriptions' ), '', '', '', '' ), - 'id' => WC_Subscriptions_Admin::$option_prefix . '_payment_gateways_additional', - 'type' => 'informational', + array( + // translators: placeholders are opening and closing link tags + 'desc' => sprintf( __( 'Payment gateways which don\'t support automatic recurring payments can be used to process %1$smanual subscription renewal payments%2$s.', 'woocommerce-subscriptions' ), '', '' ), + 'id' => WC_Subscriptions_Admin::$option_prefix . '_payment_gateways_additional', + 'type' => 'informational', + ), ), + self::$option_prefix ); $insert_index = array_search( @@ -1987,30 +1811,44 @@ class WC_Subscriptions_Admin { * Insert a setting or an array of settings after another specific setting by its ID. * * @since 2.2.20 - * @param array $settings The original list of settings. + * @param array $settings The original list of settings. Passed by reference. * @param string $insert_after_setting_id The setting id to insert the new setting after. * @param array $new_setting The new setting to insert. Can be a single setting or an array of settings. * @param string $insert_type The type of insert to perform. Can be 'single_setting' or 'multiple_settings'. Optional. Defaults to a single setting insert. + * @param string $insert_after The setting type to insert the new settings after. Optional. Default is 'first' - the setting will be inserted after the first occuring setting with the matching ID (no specific type). Pass a setting type (like 'sectionend') to insert after a setting type. */ - public static function insert_setting_after( &$settings, $insert_after_setting_id, $new_setting, $insert_type = 'single_setting' ) { + public static function insert_setting_after( &$settings, $insert_after_setting_id, $new_setting, $insert_type = 'single_setting', $insert_after = 'first' ) { if ( ! is_array( $settings ) ) { return; } $original_settings = $settings; $settings = array(); + $inserted = false; foreach ( $original_settings as $setting ) { $settings[] = $setting; + if ( $inserted ) { + continue; + } + + if ( 'first' !== $insert_after && isset( $setting['type'] ) && $setting['type'] !== $insert_after ) { + continue; + } + if ( isset( $setting['id'] ) && $insert_after_setting_id === $setting['id'] ) { if ( 'single_setting' === $insert_type ) { $settings[] = $new_setting; } else { $settings = array_merge( $settings, $new_setting ); } + + $inserted = true; } } + + return $inserted; } /** @@ -2019,7 +1857,7 @@ class WC_Subscriptions_Admin { * @param array $settings The list of settings */ public static function add_guest_checkout_setting_note( $settings ) { - $is_wc_pre_3_4_0 = WC_Subscriptions::is_woocommerce_pre( '3.4.0' ); + $is_wc_pre_3_4_0 = wcs_is_woocommerce_pre( '3.4.0' ); $current_filter = current_filter(); if ( ( $is_wc_pre_3_4_0 && 'woocommerce_payment_gateways_settings' !== $current_filter ) || ( ! $is_wc_pre_3_4_0 && 'woocommerce_account_settings' !== $current_filter ) ) { @@ -2083,6 +1921,35 @@ class WC_Subscriptions_Admin { } } + /** + * Adds a setting to allow customer registration on checkout specifically for subscription purchases. + * + * If the store allows registration on the checkout, this setting is hidden because that higher level + * setting overrides any need for a specific subscription setting. + * + * This setting allows stores to enable users to create an account when purchasing a subscription, but + * not allow an account to be created when they are making one off/standard purchases. + * + * @since 3.1.0 + * + * @param array $settings The Accounts & Privacy settings. + * @return array $settings. + */ + public static function add_registration_for_subscription_purchases_setting( $settings ) { + + self::insert_setting_after( $settings, 'woocommerce_enable_signup_and_login_from_checkout', array( + 'id' => 'woocommerce_enable_signup_from_checkout_for_subscriptions', + 'name' => __( 'Allow subscription customers to create an account during checkout', 'woocommerce-subscriptions' ), + 'desc' => __( 'Allow subscription customers to create an account during checkout', 'woocommerce-subscriptions' ), + 'default' => 'yes', + 'type' => 'checkbox', + 'checkboxgroup' => '', + 'autoload' => false, + ) ); + + return $settings; + } + /** * Renders the Subscription information in the WC status page */ @@ -2183,4 +2050,25 @@ class WC_Subscriptions_Admin { return WC_Subscriptions_Admin::filter_orders_and_subscriptions_from_list( $where ); } + + /** + * Prevents variations from being deleted if switching from a variable product type to a subscription variable product type (and vice versa). + * + * @since 3.0.14 + * + * @param bool $delete_variations A boolean value of true will delete the variations. + * @param WC_Product $product Product data. + * @return string $from Origin type. + * @param string $to New type. + * + * @return bool Whehter the variations should be deleted. + */ + public static function maybe_keep_variations( $delete_variations, $product, $from, $to ) { + + if ( ( 'variable' === $from && 'variable-subscription' === $to ) || ( 'variable-subscription' === $from && 'variable' === $to ) ) { + $delete_variations = false; + } + + return $delete_variations; + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php new file mode 100644 index 0000000..3c9e10c --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-meta-boxes.php @@ -0,0 +1,650 @@ +get_order_type( $post_ID ) && wcs_order_contains_subscription( $post_ID, 'any' ) ) { + add_meta_box( 'subscription_renewal_orders', __( 'Related Orders', 'woocommerce-subscriptions' ), 'WCS_Meta_Box_Related_Orders::output', 'shop_order', 'normal', 'low' ); + } + } + + /** + * Removes the core Order Data meta box as we add our own Subscription Data meta box + */ + public function remove_meta_boxes() { + remove_meta_box( 'woocommerce-order-data', 'shop_subscription', 'normal' ); + } + + /** + * Don't save save some order related meta boxes + */ + public function remove_meta_box_save( $post_id, $post ) { + + if ( 'shop_subscription' == $post->post_type ) { + remove_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Data::save', 40 ); + } + } + + /** + * Print admin styles/scripts + */ + public function enqueue_styles_scripts() { + global $post; + + // Get admin screen id + $screen = get_current_screen(); + $screen_id = isset( $screen->id ) ? $screen->id : ''; + + if ( 'shop_subscription' == $screen_id ) { + + wp_register_script( 'jstz', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/jstz.min.js' ) ); + + wp_register_script( 'momentjs', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/moment.min.js' ) ); + + wp_enqueue_script( 'wcs-admin-meta-boxes-subscription', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/meta-boxes-subscription.js' ), array( 'wc-admin-meta-boxes', 'jstz', 'momentjs' ), WC_VERSION ); + + wp_localize_script( 'wcs-admin-meta-boxes-subscription', 'wcs_admin_meta_boxes', apply_filters( 'woocommerce_subscriptions_admin_meta_boxes_script_parameters', array( + 'i18n_start_date_notice' => __( 'Please enter a start date in the past.', 'woocommerce-subscriptions' ), + 'i18n_past_date_notice' => WCS_Staging::is_duplicate_site() ? __( 'Please enter a date at least 2 minutes into the future.', 'woocommerce-subscriptions' ) : __( 'Please enter a date at least one hour into the future.', 'woocommerce-subscriptions' ), + 'i18n_next_payment_start_notice' => __( 'Please enter a date after the trial end.', 'woocommerce-subscriptions' ), + 'i18n_next_payment_trial_notice' => __( 'Please enter a date after the start date.', 'woocommerce-subscriptions' ), + 'i18n_trial_end_start_notice' => __( 'Please enter a date after the start date.', 'woocommerce-subscriptions' ), + 'i18n_trial_end_next_notice' => __( 'Please enter a date before the next payment.', 'woocommerce-subscriptions' ), + 'i18n_end_date_notice' => __( 'Please enter a date after the next payment.', 'woocommerce-subscriptions' ), + 'process_renewal_action_warning' => __( "Are you sure you want to process a renewal?\n\nThis will charge the customer and email them the renewal order (if emails are enabled).", 'woocommerce-subscriptions' ), + 'payment_method' => wcs_get_subscription( $post )->get_payment_method(), + 'search_customers_nonce' => wp_create_nonce( 'search-customers' ), + 'get_customer_orders_nonce' => wp_create_nonce( 'get-customer-orders' ), + 'is_duplicate_site' => WCS_Staging::is_duplicate_site(), + ) ) ); + } else if ( 'shop_order' == $screen_id ) { + + wp_enqueue_script( 'wcs-admin-meta-boxes-order', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/wcs-meta-boxes-order.js' ) ); + + wp_localize_script( + 'wcs-admin-meta-boxes-order', + 'wcs_admin_order_meta_boxes', + array( + 'retry_renewal_payment_action_warning' => __( "Are you sure you want to retry payment for this renewal order?\n\nThis will attempt to charge the customer and send renewal order emails (if emails are enabled).", 'woocommerce-subscriptions' ), + ) + ); + } + + // Enqueue the metabox script for coupons. + if ( ! wcs_is_woocommerce_pre( '3.2' ) && in_array( $screen_id, array( 'shop_coupon', 'edit-shop_coupon' ) ) ) { + wp_enqueue_script( + 'wcs-admin-coupon-meta-boxes', + WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/meta-boxes-coupon.js' ), + array( 'jquery', 'wc-admin-meta-boxes' ), + WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() + ); + } + } + + /** + * Adds actions to the admin edit subscriptions page, if the subscription hasn't ended and the payment method supports them. + * + * @param array $actions An array of available actions + * @return array An array of updated actions + * @since 2.0 + */ + public static function add_subscription_actions( $actions ) { + global $theorder; + + if ( wcs_is_subscription( $theorder ) ) { + if ( ! wcs_is_woocommerce_pre( '3.2' ) ) { + unset( $actions['send_order_details'], $actions['send_order_details_admin'] ); + } + + if ( ! $theorder->has_status( wcs_get_subscription_ended_statuses() ) ) { + if ( $theorder->payment_method_supports( 'subscription_date_changes' ) && $theorder->has_status( 'active' ) ) { + $actions['wcs_process_renewal'] = esc_html__( 'Process renewal', 'woocommerce-subscriptions' ); + } + + if ( count( $theorder->get_related_orders() ) > 0 ) { + $actions['wcs_create_pending_renewal'] = esc_html__( 'Create pending renewal order', 'woocommerce-subscriptions' ); + } else { + $actions['wcs_create_pending_parent'] = esc_html__( 'Create pending parent order', 'woocommerce-subscriptions' ); + } + } + } else if ( self::can_renewal_order_be_retried( $theorder ) ) { + $actions['wcs_retry_renewal_payment'] = esc_html__( 'Retry Renewal Payment', 'woocommerce-subscriptions' ); + } + + return $actions; + } + + /** + * Handles the action request to process a renewal order. + * + * @param array $subscription + * @since 2.0 + */ + public static function process_renewal_action_request( $subscription ) { + $subscription->add_order_note( __( 'Process renewal order action requested by admin.', 'woocommerce-subscriptions' ), false, true ); + do_action( 'woocommerce_scheduled_subscription_payment', $subscription->get_id() ); + } + + /** + * Handles the action request to create a pending renewal order. + * + * @param array $subscription + * @since 2.0 + */ + public static function create_pending_renewal_action_request( $subscription ) { + $subscription->add_order_note( __( 'Create pending renewal order requested by admin action.', 'woocommerce-subscriptions' ), false, true ); + $subscription->update_status( 'on-hold' ); + + $renewal_order = wcs_create_renewal_order( $subscription ); + + if ( ! $subscription->is_manual() ) { + + $renewal_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name + + if ( is_callable( array( $renewal_order, 'save' ) ) ) { // WC 3.0+ + $renewal_order->save(); + } + } + } + + /** + * Handles the action request to create a pending parent order. + * + * @param array $subscription + * @since 2.3 + */ + public static function create_pending_parent_action_request( $subscription ) { + + if ( ! $subscription->has_status( array( 'pending', 'on-hold' ) ) ) { + $subscription->update_status( 'on-hold' ); + } + + $parent_order = wcs_create_order_from_subscription( $subscription, 'parent' ); + + $subscription->set_parent_id( wcs_get_objects_property( $parent_order, 'id' ) ); + $subscription->save(); + + if ( ! $subscription->is_manual() ) { + + $parent_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name + + if ( is_callable( array( $parent_order, 'save' ) ) ) { // WC 3.0+ + $parent_order->save(); + } + } + + wc_maybe_reduce_stock_levels( $parent_order ); + $subscription->add_order_note( __( 'Create pending parent order requested by admin action.', 'woocommerce-subscriptions' ), false, true ); + } + + /** + * Removes order related emails from the available actions. + * + * @param array $available_emails + * @since 2.0 + */ + public static function remove_order_email_actions( $email_actions ) { + global $theorder; + + if ( wcs_is_subscription( $theorder ) ) { + $email_actions = array(); + } + + return $email_actions; + } + + /** + * Process the action request to retry renewal payment for failed renewal orders. + * + * @param WC_Order $order + * @since 2.1 + */ + public static function process_retry_renewal_payment_action_request( $order ) { + + if ( self::can_renewal_order_be_retried( $order ) ) { + // init payment gateways + WC()->payment_gateways(); + + $order->add_order_note( __( 'Retry renewal payment action requested by admin.', 'woocommerce-subscriptions' ), false, true ); + do_action( 'woocommerce_scheduled_subscription_payment_' . wcs_get_objects_property( $order, 'payment_method' ), $order->get_total(), $order ); + } + } + + /** + * Determines if a renewal order payment can be retried. A renewal order payment can only be retried when: + * - Order is a renewal order + * - Order status is failed + * - Order payment method isn't empty + * - Order total > 0 + * - Subscription/s aren't manual + * - Subscription payment method supports date changes + * - Order payment method has_action('woocommerce_scheduled_subscription_payment_..') + * + * @param WC_Order $order + * @return bool + * @since 2.1 + */ + private static function can_renewal_order_be_retried( $order ) { + + $can_be_retried = false; + + if ( wcs_order_contains_renewal( $order ) && $order->needs_payment() && '' != wcs_get_objects_property( $order, 'payment_method' ) ) { + $supports_date_changes = false; + $order_payment_gateway = wc_get_payment_gateway_by_order( $order ); + $order_payment_gateway_supports = ( isset( $order_payment_gateway->id ) ) ? has_action( 'woocommerce_scheduled_subscription_payment_' . $order_payment_gateway->id ) : false; + + foreach ( wcs_get_subscriptions_for_renewal_order( $order ) as $subscription ) { + $supports_date_changes = $subscription->payment_method_supports( 'subscription_date_changes' ); + $is_automatic = ! $subscription->is_manual(); + break; + } + + $can_be_retried = $order_payment_gateway_supports && $supports_date_changes && $is_automatic; + } + + return $can_be_retried; + } + + /** + * Disables stock managment while adding items to a subscription via the edit subscription screen. + * + * @since 3.0.6 + * + * @param string $manage_stock The default manage stock setting. + * @return string Whether the stock should be managed. + */ + public static function override_stock_management( $manage_stock ) { + + // Override stock management while adding line items to a subscription via AJAX. + if ( isset( $_POST['order_id'], $_REQUEST['security'] ) && wp_verify_nonce( $_REQUEST['security'], 'order-item' ) && doing_action( 'wp_ajax_woocommerce_add_order_item' ) && wcs_is_subscription( absint( wp_unslash( $_POST['order_id'] ) ) ) ) { + $manage_stock = 'no'; + } + + return $manage_stock; + } + + + /** + * Displays a checkbox allowing admin to lock in prices increases in the edit order line items meta box. + * + * This checkbox is only displayed if the following criteria is met: + * - The order is unpaid. + * - The order is a subscription parent order. Renewal orders already lock in the subscription recurring price. + * - The order's currency matches the base store currency. + * - The order contains a line item with a subtotal greater than the product's current live price. + * + * @since 3.0.10 + * + * @param WC_Order $order The order being edited. + */ + public static function output_price_lock_html( $order ) { + + if ( ! $order->needs_payment() || ! wcs_order_contains_subscription( $order, 'parent' ) ) { + return; + } + + // If the order currency doesn't match the base currency we can't know if the order contains manually increased prices. + if ( $order->get_currency() !== get_woocommerce_currency() ) { + return; + } + + $needs_price_lock = false; + + foreach ( $order->get_items() as $line_item ) { + $product = $line_item->get_product(); + + // If the line item price is above the current live price. + if ( $product && ( $line_item->get_subtotal() / $line_item->get_quantity() ) > $product->get_price() ) { + $needs_price_lock = true; + break; + } + } + + if ( $needs_price_lock ) { + $help_tip = __( "This order contains line items with prices above the current product price. To override the product's live price when the customer pays for this order, lock in the manual price increases.", 'woocommerce-subscriptions' ); + + printf( + '

    %s
    ', + esc_html__( 'Lock manual price increases', 'woocommerce-subscriptions' ), + // So the help tip is initialized when the line items are reloaded, we need to add the 'tips' class to the element. + wcs_help_tip( $help_tip, false, 'woocommerce-help-tip tips' ), + checked( $order->get_meta( '_manual_price_increases_locked' ), 'true', false ) + ); + } + } + + /** + * Saves the manual price increase lock via Edit order save and ajax request. + * + * @since 3.0.10 + * + * @param string $order_id Optional. The order ID. For non-ajax requests, this parameter is required. + */ + public static function save_increased_price_lock( $order_id = '' ) { + + if ( empty( $_POST['woocommerce_meta_nonce'] ) || ! wp_verify_nonce( $_POST['woocommerce_meta_nonce'], 'woocommerce_save_data' ) ) { + return; + } + + $order = wc_get_order( wp_doing_ajax() && isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : $order_id ); + + if ( ! $order ) { + return; + } + + if ( isset( $_POST['wcs_order_price_lock'] ) && 'yes' === wc_clean( $_POST['wcs_order_price_lock'] ) ) { + $order->update_meta_data( '_manual_price_increases_locked', 'true' ); + $order->save(); + } elseif ( $order->meta_exists( '_manual_price_increases_locked' ) ) { + $order->delete_meta_data( '_manual_price_increases_locked' ); + $order->save(); + } + } + + /** + * Stores the subtracted base location tax totals for subscription and renewal line items. + * + * @since 3.0.10 + * + * @param int $item_id The ID of the order item added. + * @param WC_Order_Item_Product $line_item The line item added. + * @param WC_Abstract_Order $order The order or subscription the product was added to. + */ + public static function store_item_base_location_tax( $item_id, $line_item, $order ) { + if ( ! apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) { + return; + } + + if ( ! wc_prices_include_tax() ) { + return; + } + + if ( ! wcs_is_subscription( $order ) && ! wcs_order_contains_renewal( $order ) ) { + return; + } + + if ( '0' !== $line_item->get_tax_class() && 'taxable' === $line_item->get_tax_status() ) { + $base_tax_rates = WC_Tax::get_base_tax_rates( $line_item->get_tax_class() ); + + /** + * Find the tax rates that apply to the line item given the current order's address and on what tax calculations are based off. + */ + $tax_based_on = get_option( 'woocommerce_tax_based_on' ); + + // If tax calculations are based on the base store location, exit since we know the rates will match. + if ( 'base' === $tax_based_on ) { + return; + } + + if ( 'shipping' === $tax_based_on && ! $order->get_shipping_country() ) { + $tax_based_on = 'billing'; + } + + $applicable_tax_rates = WC_Tax::find_rates( + array( + 'country' => 'billing' === $tax_based_on ? $order->get_billing_country() : $order->get_shipping_country(), + 'state' => 'billing' === $tax_based_on ? $order->get_billing_state() : $order->get_shipping_state(), + 'postcode' => 'billing' === $tax_based_on ? $order->get_billing_postcode() : $order->get_shipping_postcode(), + 'city' => 'billing' === $tax_based_on ? $order->get_billing_city() : $order->get_shipping_city(), + 'tax_class' => $line_item->get_tax_class(), + ) + ); + + if ( $applicable_tax_rates === $base_tax_rates ) { + return; + } + + $line_item->update_meta_data( '_subtracted_base_location_taxes', WC_Tax::calc_tax( $line_item->get_product()->get_price(), $base_tax_rates, true ) ); + $line_item->update_meta_data( '_subtracted_base_location_rates', $base_tax_rates ); + $line_item->save(); + } + } + + /** + * Prevents WC core's handling of stock for subscriptions saved via the edit subscription screen. + * + * Hooked onto 'woocommerce_prevent_adjust_line_item_product_stock' which is triggered in + * wc_maybe_adjust_line_item_product_stock() via: + * - WC_AJAX::remove_order_item(). + * - wc_save_order_items(). + * + * @since 3.1.0 + * + * @param WC_Order_Item $item The line item being saved/updated via the edit subscription screen. + * @return bool Whether to reduce stock for the line item. + */ + public static function prevent_subscription_line_item_stock_handling( $prevent_stock_handling, $item ) { + + if ( wcs_is_subscription( $item->get_order_id() ) ) { + $prevent_stock_handling = true; + } + + return $prevent_stock_handling; + } + + /** + * Updates the `_subtracted_base_location_tax` meta when admin users update a line item's quantity. + * + * @since 3.0.14 + * + * @param int $order_id The edited order or subscription ID. + * @param array $item_data An array of data about all line item changes. + */ + public static function update_subtracted_base_location_tax_meta( $order_id, $item_data ) { + + // We're only interested in item quantity changes. + if ( ! isset( $item_data['order_item_qty'] ) ) { + return; + } + + $is_subscription = wcs_is_subscription( $order_id ); + + // We only need to update subscription and renewal order `_subtracted_base_location_tax` meta data. + if ( ! $is_subscription && ! wcs_order_contains_renewal( $order_id ) ) { + return; + } + + $object = $is_subscription ? wcs_get_subscription( $order_id ) : wc_get_order( $order_id ); + + if ( ! $object ) { + return; + } + + foreach ( $object->get_items() as $line_item ) { + // If the line item is tracking the base store location tax amount and the quantity has changed, hook in the function to update that item's meta. + if ( $line_item->meta_exists( '_subtracted_base_location_tax' ) ) { + if ( isset( $item_data['order_item_qty'][ $line_item->get_id() ] ) && $item_data['order_item_qty'][ $line_item->get_id() ] !== $line_item->get_quantity() ) { + $current_base_location_taxes = $line_item->get_meta( '_subtracted_base_location_tax' ); + $previous_quantity = $line_item->get_quantity(); + $new_quantity = $item_data['order_item_qty'][ $line_item->get_id() ]; + $new_base_taxes = array(); + + // Update all the base taxes for the new quantity. + foreach ( $current_base_location_taxes as $rate_id => $tax_amount ) { + $new_base_taxes[ $rate_id ] = ( $tax_amount / $previous_quantity ) * $new_quantity; + } + + $line_item->update_meta_data( '_subtracted_base_location_tax', $new_base_taxes ); + $line_item->save(); + } + } + } + } + + /** + * Updates the `_subtracted_base_location_taxes` meta when admin users update a line item's price. + * + * @since 3.1.0 + * + * @param int $order_id The edited order or subscription ID. + * @param array $item_data An array of data about all line item changes. + */ + public static function update_subtracted_base_location_taxes_amount( $order_id, $item_data ) { + // We're only interested in item subtotal changes. + if ( ! isset( $item_data['line_subtotal'] ) || ! is_array( $item_data['line_subtotal'] ) ) { + return; + } + + $is_subscription = wcs_is_subscription( $order_id ); + + // We only need to update subscription and renewal order `_subtracted_base_location_taxes` meta data. + if ( ! $is_subscription && ! wcs_order_contains_renewal( $order_id ) ) { + return; + } + + $object = $is_subscription ? wcs_get_subscription( $order_id ) : wc_get_order( $order_id ); + + if ( ! $object ) { + return; + } + + foreach ( $item_data['line_subtotal'] as $line_item_id => $new_line_subtotal ) { + $line_item = WC_Order_Factory::get_order_item( $line_item_id ); + + // If this item's subtracted tax data hasn't been repaired, do that now. + if ( $line_item->meta_exists( '_subtracted_base_location_tax' ) ) { + WC_Subscriptions_Upgrader::repair_subtracted_base_taxes( $line_item->get_id() ); + $line_item = WC_Order_Factory::get_order_item( $line_item->get_id() ); + } + + if ( ! $line_item->meta_exists( '_subtracted_base_location_taxes' ) ) { + continue; + } + + $new_line_subtotal = wc_format_decimal( $new_line_subtotal ); + $current_base_location_taxes = $line_item->get_meta( '_subtracted_base_location_taxes' ); + $old_line_subtotal = $line_item->get_subtotal(); + $old_line_quantity = $line_item->get_quantity(); + $new_line_quantity = absint( $item_data['order_item_qty'][ $line_item_id ] ); + + if ( $line_item->meta_exists( '_subtracted_base_location_rates' ) ) { + $base_tax_rates = $line_item->get_meta( '_subtracted_base_location_rates' ); + $product_price = ( $new_line_subtotal + array_sum( WC_Tax::calc_exclusive_tax( $new_line_subtotal, $base_tax_rates ) ) ) / $new_line_quantity; + + $new_base_taxes = WC_Tax::calc_tax( $product_price, $base_tax_rates, true ); + } else { + // Update all the base taxes for the new product subtotal. + foreach ( $current_base_location_taxes as $rate_id => $tax_amount ) { + $new_base_taxes[ $rate_id ] = ( ( $new_line_subtotal / $new_line_quantity ) / ( $old_line_subtotal / $old_line_quantity ) ) * $tax_amount; + } + } + + $line_item->update_meta_data( '_subtracted_base_location_taxes', $new_base_taxes ); + $line_item->save(); + } + } + + /** + * Gets a list of customer orders via ajax. + * + * Populates the parent order list on the edit subscription screen with orders belonging to the customer. + * + * @since 4.0.0 + */ + public static function get_customer_orders() { + check_ajax_referer( 'get-customer-orders', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) ) { + wp_die( -1 ); + } + + $customer_orders = array(); + $user_id = absint( $_POST['user_id'] ); + $orders = wc_get_orders( + array( + 'customer' => $user_id, + 'post_type' => 'shop_order', + 'posts_per_page' => '-1', + ) + ); + + + foreach ( $orders as $order ) { + $customer_orders[ $order->get_id() ] = $order->get_order_number(); + } + + wp_send_json( $customer_orders ); + } +} diff --git a/includes/admin/class-wcs-admin-notice.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-notice.php similarity index 98% rename from includes/admin/class-wcs-admin-notice.php rename to vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-notice.php index 80d468f..19f6f57 100644 --- a/includes/admin/class-wcs-admin-notice.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-notice.php @@ -91,7 +91,7 @@ class WCS_Admin_Notice { } $template_name = 'html-admin-notice.php'; - $template_path = plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/'; + $template_path = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/' ); if ( function_exists( 'wc_get_template' ) ) { wc_get_template( $template_name, array( 'notice' => $this ), '', $template_path ); diff --git a/includes/admin/class-wcs-admin-post-types.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php similarity index 95% rename from includes/admin/class-wcs-admin-post-types.php rename to vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php index f3c2ec8..5c9a945 100644 --- a/includes/admin/class-wcs-admin-post-types.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php @@ -174,7 +174,7 @@ class WCS_Admin_Post_Types { $wpdb->query( "DROP TEMPORARY TABLE IF EXISTS {$table_name}" ); $wpdb->query( - "CREATE TEMPORARY TABLE {$table_name} (id INT, INDEX USING BTREE (id), last_payment DATETIME) AS + "CREATE TEMPORARY TABLE {$table_name} (id INT PRIMARY KEY, last_payment DATETIME) AS SELECT pm.meta_value as id, MAX( p.post_date_gmt ) as last_payment FROM {$wpdb->postmeta} pm LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = '_subscription_renewal' @@ -272,18 +272,18 @@ class WCS_Admin_Post_Types { ?> cancel_order( $order_note ); } else { $subscription->update_status( $new_status, $order_note, true ); @@ -361,7 +364,7 @@ class WCS_Admin_Post_Types { } $sendback_args['changed'] = $changed; - $sendback = add_query_arg( $sendback_args, wp_get_referer() ? wp_get_referer() : '' ); + $sendback = add_query_arg( $sendback_args, wp_get_referer() ? wp_get_referer() : '' ); wp_safe_redirect( esc_url_raw( $sendback ) ); exit(); @@ -436,7 +439,7 @@ class WCS_Admin_Post_Types { /** * Output custom columns for subscriptions - * @param string $column + * @param string $column */ public function render_shop_subscription_columns( $column ) { global $post, $the_subscription, $wp_list_table; @@ -445,6 +448,28 @@ class WCS_Admin_Post_Types { $the_subscription = wcs_get_subscription( $post->ID ); } + // If the subscription failed to load, only display the ID. + if ( empty( $the_subscription ) ) { + if ( 'order_title' === $column ) { + // translators: placeholder is a subscription ID. + echo '' . sprintf( esc_html_x( '#%s', 'hash before subscription number', 'woocommerce-subscriptions' ), esc_html( $post->ID ) ) . ''; + ?> + + $the_subscription->get_id(), + // Using the bulk actions nonce name as defined in WP core. '_wpnonce' => wp_create_nonce( 'bulk-posts' ), ) ); @@ -608,7 +634,7 @@ class WCS_Admin_Post_Types { // translators: placeholder is the display name of a payment gateway a subscription was paid by $column_content .= esc_html( sprintf( __( 'Via %s', 'woocommerce-subscriptions' ), $the_subscription->get_payment_method_to_display() ) ); - if ( WC_Subscriptions::is_duplicate_site() && $the_subscription->has_payment_gateway() && ! $the_subscription->get_requires_manual_renewal() ) { + if ( WCS_Staging::is_duplicate_site() && $the_subscription->has_payment_gateway() && ! $the_subscription->get_requires_manual_renewal() ) { $column_content .= WCS_Staging::get_payment_method_tooltip( $the_subscription ); } @@ -1091,7 +1117,7 @@ class WCS_Admin_Post_Types { global $typenow; // Prior to WC 3.3 this was handled by WC core so exit early if an earlier version of WC is active. - if ( 'shop_subscription' !== $typenow || WC_Subscriptions::is_woocommerce_pre( '3.3' ) ) { + if ( 'shop_subscription' !== $typenow || wcs_is_woocommerce_pre( '3.3' ) ) { return; } diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-product-import-export-manager.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-product-import-export-manager.php new file mode 100644 index 0000000..a3c821b --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-product-import-export-manager.php @@ -0,0 +1,107 @@ + $product_type ) { + if ( 'subscription_variation' === $product_type ) { + $export_subscription_variations = true; + + // All variation products are exported with the 'variation' key so remove the uneeded `subscription_variation`. + // Further filtering by product type will be handled by the query args (see below). + unset( $args['type'][ $index ] ); + } elseif ( 'variation' === $product_type ) { + $export_variations = true; + } + } + + // Exporting subscription variations but not standard variations. Exclude child variations of variable products. + if ( $export_subscription_variations && ! $export_variations ) { + $args['parent_exclude'] = wc_get_products( + array( + 'type' => 'variable', + 'limit' => -1, + 'return' => 'ids', + ) + ); + + $args['type'][] = 'variation'; + // Exporting standard product variations but not subscription variations. Exclude child variations of subscription variable products. + } elseif ( $export_variations && ! $export_subscription_variations ) { + $args['parent_exclude'] = wc_get_products( + array( + 'type' => 'variable-subscription', + 'limit' => -1, + 'return' => 'ids', + ) + ); + } + + return $args; + } + + /** + * Filters product import data so subcription variations are imported correctly (as variations). + * + * Subscription variations are the exact same as standard variations. What sets them apart is the fact they are linked + * to a variable subscription parent rather than a standard variable product. With that in mind, we need to import them just + * like a variation. + * + * @param array $data The product's import data. + * @return array $data + */ + public static function import_subscription_variations( $data ) { + if ( isset( $data['type'] ) && 'subscription_variation' === $data['type'] ) { + $data['type'] = 'variation'; + } + + return $data; + } +} diff --git a/includes/admin/class-wcs-admin-system-status.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php similarity index 87% rename from includes/admin/class-wcs-admin-system-status.php rename to vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php index da0f301..380d380 100644 --- a/includes/admin/class-wcs-admin-system-status.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php @@ -79,7 +79,7 @@ class WCS_Admin_System_Status { $section_tooltip = $section['tooltip']; $debug_data = $section['data']; - include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/status.php' ); + include( WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/status.php' ) ); } } @@ -106,8 +106,8 @@ class WCS_Admin_System_Status { $debug_data['wcs_staging'] = array( 'name' => _x( 'Subscriptions Mode', 'Live or Staging, Label on WooCommerce -> System Status page', 'woocommerce-subscriptions' ), 'label' => 'Subscriptions Mode', - 'note' => '' . ( ( WC_Subscriptions::is_duplicate_site() ) ? _x( 'Staging', 'refers to staging site', 'woocommerce-subscriptions' ) : _x( 'Live', 'refers to live site', 'woocommerce-subscriptions' ) ) . '', - 'success' => ( WC_Subscriptions::is_duplicate_site() ) ? 0 : 1, + 'note' => '' . ( ( WCS_Staging::is_duplicate_site() ) ? _x( 'Staging', 'refers to staging site', 'woocommerce-subscriptions' ) : _x( 'Live', 'refers to live site', 'woocommerce-subscriptions' ) ) . '', + 'success' => ( WCS_Staging::is_duplicate_site() ) ? 0 : 1, ); } @@ -118,7 +118,7 @@ class WCS_Admin_System_Status { $debug_data['wcs_live_site_url'] = array( 'name' => _x( 'Subscriptions Live URL', 'Live URL, Label on WooCommerce -> System Status page', 'woocommerce-subscriptions' ), 'label' => 'Subscriptions Live URL', - 'note' => '' . esc_html( WC_Subscriptions::get_site_url_from_source( 'subscriptions_install' ) ) . '', + 'note' => '' . esc_html( WCS_Staging::get_site_url_from_source( 'subscriptions_install' ) ) . '', 'mark' => '', 'mark_icon' => '', ); @@ -155,7 +155,7 @@ class WCS_Admin_System_Status { * @return array Theme override data. */ private static function get_theme_overrides() { - $wcs_template_dir = dirname( WC_Subscriptions::$plugin_file ) . '/templates/'; + $wcs_template_dir = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ); $wc_template_path = trailingslashit( wc()->template_path() ); $theme_root = trailingslashit( get_theme_root() ); $overridden = array(); @@ -208,21 +208,12 @@ class WCS_Admin_System_Status { */ private static function set_subscription_statuses( &$debug_data ) { - $subscriptions_by_status = (array) wp_count_posts( 'shop_subscription' ); - $subscriptions_by_status_output = array(); - - foreach ( $subscriptions_by_status as $status => $count ) { - if ( ! empty( $count ) ) { - $subscriptions_by_status_output[] = $status . ': ' . $count; - } - } - $debug_data['wcs_subscriptions_by_status'] = array( 'name' => _x( 'Subscription Statuses', 'label for the system status page', 'woocommerce-subscriptions' ), 'label' => 'Subscription Statuses', 'mark' => '', 'mark_icon' => '', - 'data' => $subscriptions_by_status_output, + 'data' => self::get_subscription_statuses(), ); } @@ -273,21 +264,9 @@ class WCS_Admin_System_Status { * Add a breakdown of subscriptions per payment gateway. */ private static function set_subscriptions_by_payment_gateway( &$debug_data ) { - global $wpdb; - $gateways = WC()->payment_gateways->get_available_payment_gateways(); - $results = $wpdb->get_results( " - SELECT COUNT(subscriptions.ID) as count, post_meta.meta_value as payment_method, subscriptions.post_status - FROM $wpdb->posts as subscriptions RIGHT JOIN $wpdb->postmeta as post_meta ON post_meta.post_id = subscriptions.ID - WHERE subscriptions.post_type = 'shop_subscription' && post_meta.meta_key = '_payment_method' - GROUP BY post_meta.meta_value, subscriptions.post_status", ARRAY_A ); - - $subscriptions_payment_gateway_data = array(); - - foreach ( $results as $result ) { - $payment_method = $result['payment_method']; - $subscription_status = $result['post_status']; + foreach ( self::get_subscriptions_by_gateway() as $payment_method => $status_counts ) { if ( isset( $gateways[ $payment_method ] ) ) { $payment_method_name = $payment_method_label = $gateways[ $payment_method ]->method_title; } else { @@ -297,15 +276,15 @@ class WCS_Admin_System_Status { $key = 'wcs_payment_method_subscriptions_by' . $payment_method; - if ( ! isset( $debug_data[ $key ] ) ) { - $debug_data[ $key ] = array( - 'name' => $payment_method_name, - 'label' => $payment_method_label, - 'data' => array(), - ); - } + $debug_data[ $key ] = array( + 'name' => $payment_method_name, + 'label' => $payment_method_label, + 'data' => array(), + ); - $debug_data[ $key ]['data'][] = $subscription_status . ': ' . $result['count']; + foreach ( $status_counts as $status => $count ) { + $debug_data[ $key ]['data'][] = "$status: $count"; + } } } @@ -361,4 +340,46 @@ class WCS_Admin_System_Status { 'mark_icon' => '', ); } + + /** + * Gets the store's subscription broken down by payment gateway and status. + * + * @since 3.1.0 + * @return array The subscription gateway and status data array( 'gateway_id' => array( 'status' => count ) ); + */ + public static function get_subscriptions_by_gateway() { + global $wpdb; + $subscription_gatway_data = array(); + + $results = $wpdb->get_results( " + SELECT COUNT(subscriptions.ID) as count, post_meta.meta_value as payment_method, subscriptions.post_status + FROM $wpdb->posts as subscriptions RIGHT JOIN $wpdb->postmeta as post_meta ON post_meta.post_id = subscriptions.ID + WHERE subscriptions.post_type = 'shop_subscription' && post_meta.meta_key = '_payment_method' + GROUP BY post_meta.meta_value, subscriptions.post_status", ARRAY_A ); + + foreach ( $results as $result ) { + $subscription_gatway_data[ $result['payment_method'] ][ $result['post_status'] ] = $result['count']; + } + + return $subscription_gatway_data; + } + + /** + * Gets the store's subscriptions by status. + * + * @since 3.1.0 + * @return array + */ + public static function get_subscription_statuses() { + $subscriptions_by_status = (array) wp_count_posts( 'shop_subscription' ); + $subscriptions_by_status_output = array(); + + foreach ( $subscriptions_by_status as $status => $count ) { + if ( ! empty( $count ) ) { + $subscriptions_by_status_output[] = $status . ': ' . $count; + } + } + + return $subscriptions_by_status_output; + } } diff --git a/includes/admin/class-wcs-wc-admin-manager.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php similarity index 64% rename from includes/admin/class-wcs-wc-admin-manager.php rename to vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php index c45dec7..d415e0a 100644 --- a/includes/admin/class-wcs-wc-admin-manager.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php @@ -2,12 +2,14 @@ /** * WooCommerce Subscriptions WC Admin Manager. * - * @author WooCommerce - * @category Admin * @package WooCommerce Subscriptions/Admin * @version 3.0.2 */ +use Automattic\WooCommerce\Admin\Loader; +use Automattic\WooCommerce\Admin\Features\Navigation\Menu; +use Automattic\WooCommerce\Admin\Features\Navigation\Screen; + defined( 'ABSPATH' ) || exit; class WCS_WC_Admin_Manager { @@ -21,6 +23,7 @@ class WCS_WC_Admin_Manager { } add_action( 'admin_menu', array( __CLASS__, 'register_subscription_admin_pages' ) ); + add_action( 'admin_menu', array( __CLASS__, 'register_navigation_items' ), 6 ); } /** @@ -57,4 +60,28 @@ class WCS_WC_Admin_Manager { ) ); } + + /** + * Register the navigation items in the WooCommerce navigation. + * + * @since 3.0.12 + */ + public static function register_navigation_items() { + if ( + ! class_exists( '\Automattic\WooCommerce\Admin\Features\Navigation\Menu' ) || + ! class_exists( '\Automattic\WooCommerce\Admin\Features\Navigation\Screen' ) + ) { + return; + } + + $subscription_items = Menu::get_post_type_items( + 'shop_subscription', + array( + 'title' => __( 'Subscriptions', 'woocommerce-subscriptions' ), + ) + ); + + Menu::add_plugin_item( $subscription_items['all'] ); + Screen::register_post_type( 'shop_subscription' ); + } } diff --git a/includes/admin/debug-tools/class-wcs-debug-tool-cache-background-updater.php b/vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-cache-background-updater.php similarity index 100% rename from includes/admin/debug-tools/class-wcs-debug-tool-cache-background-updater.php rename to vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-cache-background-updater.php diff --git a/includes/admin/debug-tools/class-wcs-debug-tool-cache-eraser.php b/vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-cache-eraser.php similarity index 100% rename from includes/admin/debug-tools/class-wcs-debug-tool-cache-eraser.php rename to vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-cache-eraser.php diff --git a/includes/admin/debug-tools/class-wcs-debug-tool-cache-generator.php b/vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-cache-generator.php similarity index 100% rename from includes/admin/debug-tools/class-wcs-debug-tool-cache-generator.php rename to vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-cache-generator.php diff --git a/includes/admin/debug-tools/class-wcs-debug-tool-factory.php b/vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-factory.php similarity index 100% rename from includes/admin/debug-tools/class-wcs-debug-tool-factory.php rename to vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-debug-tool-factory.php diff --git a/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php similarity index 98% rename from includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php index 2639317..80fdd98 100644 --- a/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php @@ -117,6 +117,8 @@ class WCS_Meta_Box_Related_Orders { $orders_to_display = apply_filters( 'woocommerce_subscriptions_admin_related_orders_to_display', $orders_to_display, $subscriptions, $post ); + wcs_sort_objects( $orders_to_display, 'date_created', 'descending' ); + foreach ( $orders_to_display as $order ) { // Skip the order being viewed. if ( $order->get_id() === (int) $post->ID ) { diff --git a/includes/admin/meta-boxes/class-wcs-meta-box-schedule.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-schedule.php similarity index 100% rename from includes/admin/meta-boxes/class-wcs-meta-box-schedule.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-schedule.php diff --git a/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php similarity index 99% rename from includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php index ffecdd2..bc9893d 100644 --- a/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php @@ -355,7 +355,7 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data { } // Update shipping fields. - foreach ( self::$billing_fields as $key => $field ) { + foreach ( self::$shipping_fields as $key => $field ) { $field['id'] = isset( $field['id'] ) ? $field['id'] : "_shipping_{$key}"; if ( ! isset( $_POST[ $field['id'] ] ) ) { @@ -364,7 +364,7 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data { $value = wc_clean( wp_unslash( $_POST[ $field['id'] ] ) ); - if ( is_callable( array( $subscription, 'set_billing_' . $key ) ) ) { + if ( is_callable( array( $subscription, 'set_shipping_' . $key ) ) ) { $props[ "shipping_{$key}" ] = $value; } else { $subscription->update_meta_data( $field['id'], $value ); diff --git a/includes/admin/meta-boxes/views/html-related-orders-row.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-row.php similarity index 65% rename from includes/admin/meta-boxes/views/html-related-orders-row.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-row.php index 978c05a..2df2113 100644 --- a/includes/admin/meta-boxes/views/html-related-orders-row.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-row.php @@ -8,14 +8,10 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } - -// WC 3.0+ compatibility -$order_post = wcs_get_objects_property( $order, 'post' ); - ?> - + get_order_number() ) ); @@ -23,20 +19,24 @@ $order_post = wcs_get_objects_property( $order, 'post' ); - + get_meta( '_relationship' ) ); ?> getTimestamp(); - if ( $timestamp_gmt > 0 ) { - // translators: php date format - $t_time = get_the_time( _x( 'Y/m/d g:i:s A', 'post date', 'woocommerce-subscriptions' ), $order_post ); - $date_to_display = ucfirst( wcs_get_human_time_diff( $timestamp_gmt ) ); + $date_created = $order->get_date_created(); + + if ( $date_created ) { + $t_time = $order->get_date_created()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ); + $date_to_display = ucfirst( wcs_get_human_time_diff( $date_created->getTimestamp() ) ); } else { $t_time = $date_to_display = __( 'Unpublished', 'woocommerce-subscriptions' ); - } ?> + } + + // Backwards compatibility for third-parties using the generic WP post time filter. + $date_to_display = apply_filters( 'post_date_column_time', $date_to_display, get_post( $order->get_id() ) ); + ?> - + diff --git a/includes/admin/meta-boxes/views/html-related-orders-table.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php similarity index 100% rename from includes/admin/meta-boxes/views/html-related-orders-table.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php diff --git a/includes/admin/meta-boxes/views/html-subscription-schedule.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php similarity index 100% rename from includes/admin/meta-boxes/views/html-subscription-schedule.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-subscription-schedule.php diff --git a/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php similarity index 64% rename from includes/admin/meta-boxes/views/html-unknown-related-orders-row.php rename to vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php index e581cce..a83dcd2 100644 --- a/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php @@ -18,7 +18,12 @@ if ( ! defined( 'ABSPATH' ) ) { echo sprintf( esc_html_x( '#%s', 'hash before order number', 'woocommerce-subscriptions' ), esc_html( $order_id ) ); ?> diff --git a/includes/admin/wcs-admin-functions.php b/vendor/woocommerce/subscriptions-core/includes/admin/wcs-admin-functions.php similarity index 100% rename from includes/admin/wcs-admin-functions.php rename to vendor/woocommerce/subscriptions-core/includes/admin/wcs-admin-functions.php diff --git a/includes/class-wc-product-subscription-variation.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-product-subscription-variation.php similarity index 97% rename from includes/class-wc-product-subscription-variation.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-product-subscription-variation.php index e1b095f..d14ab33 100644 --- a/includes/class-wc-product-subscription-variation.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-product-subscription-variation.php @@ -95,7 +95,7 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation { public function add_to_cart_text() { if ( $this->is_purchasable() && $this->is_in_stock() ) { - $text = get_option( WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text', __( 'Sign up now', 'woocommerce-subscriptions' ) ); + $text = WC_Subscriptions_Product::get_add_to_cart_text(); } else { $text = parent::add_to_cart_text(); // translated "Read More" } diff --git a/includes/class-wc-product-subscription.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-product-subscription.php similarity index 100% rename from includes/class-wc-product-subscription.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-product-subscription.php diff --git a/includes/class-wc-product-variable-subscription.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-product-variable-subscription.php similarity index 98% rename from includes/class-wc-product-variable-subscription.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-product-variable-subscription.php index 90a7316..1848935 100644 --- a/includes/class-wc-product-variable-subscription.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-product-variable-subscription.php @@ -47,7 +47,7 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable { */ public function __get( $key ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $value = parent::__get( $key ); } else { $value = wcs_product_deprecated_property_handler( $key, $this ); @@ -70,7 +70,7 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable { public function single_add_to_cart_text() { if ( $this->is_purchasable() && $this->is_in_stock() ) { - $text = get_option( WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text', __( 'Sign up now', 'woocommerce-subscriptions' ) ); + $text = WC_Subscriptions_Product::get_add_to_cart_text(); } else { $text = parent::add_to_cart_text(); // translated "Read More" } @@ -197,6 +197,8 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable { $this->add_meta_data( '_min_max_variation_data', $min_and_max_data, true ); $this->add_meta_data( '_min_max_variation_ids_hash', $this->get_variation_ids_hash( $variation_ids ), true ); + + do_action( 'wc_subscriptions_min_and_max_variation_data_set', $this, $min_and_max_data, $variation_ids ); } /** diff --git a/includes/class-wc-subscription-item-coupon-pending-switch.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-item-coupon-pending-switch.php similarity index 100% rename from includes/class-wc-subscription-item-coupon-pending-switch.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-item-coupon-pending-switch.php diff --git a/includes/class-wc-subscription-item-fee-pending-switch.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-item-fee-pending-switch.php similarity index 100% rename from includes/class-wc-subscription-item-fee-pending-switch.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-item-fee-pending-switch.php diff --git a/includes/class-wc-subscription-line-item-removed.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-line-item-removed.php similarity index 100% rename from includes/class-wc-subscription-line-item-removed.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-line-item-removed.php diff --git a/includes/class-wc-subscription-line-item-switched.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-line-item-switched.php similarity index 100% rename from includes/class-wc-subscription-line-item-switched.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscription-line-item-switched.php diff --git a/includes/class-wc-subscription.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php similarity index 97% rename from includes/class-wc-subscription.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php index f5952b2..cf4dfe7 100644 --- a/includes/class-wc-subscription.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php @@ -135,7 +135,7 @@ class WC_Subscription extends WC_Order { */ public function __isset( $key ) { - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) && in_array( $key, $this->deprecated_properties ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) && in_array( $key, $this->deprecated_properties ) ) { $is_set = true; @@ -188,7 +188,7 @@ class WC_Subscription extends WC_Order { break; } - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { wcs_doing_it_wrong( $key, sprintf( 'Subscription properties should not be set directly as WooCommerce 3.0 no longer supports direct property access. Use %s instead.', $function ), '2.2.0' ); } } else { @@ -235,7 +235,7 @@ class WC_Subscription extends WC_Order { break; } - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { wcs_doing_it_wrong( $key, sprintf( 'Subscription properties should not be accessed directly as WooCommerce 3.0 no longer supports direct property access. Use %s instead.', $function ), '2.2.0' ); } } else { @@ -329,7 +329,7 @@ class WC_Subscription extends WC_Order { $can_be_updated = true; } elseif ( $this->has_status( 'pending' ) ) { $can_be_updated = true; - } elseif ( $this->has_status( 'pending-cancel' ) && ( $this->is_manual() || ( false === $this->payment_method_supports( 'gateway_scheduled_payments' ) && $this->payment_method_supports( 'subscription_date_changes' ) && $this->payment_method_supports( 'subscription_reactivation' ) ) ) ) { + } elseif ( $this->has_status( 'pending-cancel' ) && $this->get_time( 'end' ) > gmdate( 'U' ) && ( $this->is_manual() || ( false === $this->payment_method_supports( 'gateway_scheduled_payments' ) && $this->payment_method_supports( 'subscription_date_changes' ) && $this->payment_method_supports( 'subscription_reactivation' ) ) ) ) { $can_be_updated = true; } else { $can_be_updated = false; @@ -350,9 +350,17 @@ class WC_Subscription extends WC_Order { $can_be_updated = false; } break; - case 'pending-cancel': - if ( $this->payment_method_supports( 'subscription_cancellation' ) && ( $this->has_status( 'active' ) || $this->has_status( 'on-hold' ) && ! $this->needs_payment() ) ) { - $can_be_updated = true; + case 'pending-cancel' : + // Only active subscriptions can be given the "pending cancellation" status, becuase it is used to account for a prepaid term + if ( $this->payment_method_supports( 'subscription_cancellation' ) ) { + if ( $this->has_status( 'active' ) ) { + $can_be_updated = true; + } elseif ( ! $this->needs_payment() && $this->has_status( array( 'cancelled', 'on-hold' ) ) ) { + // Payment completed and subscription is cancelled + $can_be_updated = true; + } else { + $can_be_updated = false; + } } else { $can_be_updated = false; } @@ -611,8 +619,9 @@ class WC_Subscription extends WC_Order { * @return bool */ public function is_manual() { + $gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); - if ( WC_Subscriptions::is_duplicate_site() || true === $this->get_requires_manual_renewal() || false === wc_get_payment_gateway_by_order( $this ) ) { + if ( WCS_Staging::is_duplicate_site() || true === $this->get_requires_manual_renewal() || false === $gateways_handler::has_available_payment_method( $this ) ) { $is_manual = true; } else { $is_manual = false; @@ -1460,7 +1469,7 @@ class WC_Subscription extends WC_Order { // The next payment date is {interval} billing periods from the start date, trial end date or last payment date if ( 0 !== $next_payment_time && $next_payment_time < gmdate( 'U' ) && ( ( 0 !== $trial_end_time && 1 >= $this->get_payment_count() ) || WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $this ) ) ) { $from_timestamp = $next_payment_time; - } elseif ( $last_payment_time > $start_time && apply_filters( 'wcs_calculate_next_payment_from_last_payment', true, $this ) ) { + } elseif ( $last_payment_time >= $start_time && apply_filters( 'wcs_calculate_next_payment_from_last_payment', true, $this ) ) { $from_timestamp = $last_payment_time; } elseif ( $next_payment_time > $start_time ) { // Use the currently scheduled next payment to preserve synchronisation $from_timestamp = $next_payment_time; @@ -2028,7 +2037,9 @@ class WC_Subscription extends WC_Order { /** * Save new payment method for a subscription * - * @since 2.0 + * @since 2.0.0 + * + * @throws InvalidArgumentException An exception is thrown via @see WC_Subscription::set_payment_method_meta() if the payment meta passed is invalid. * @param WC_Payment_Gateway|string $payment_method * @param array $payment_meta Associated array of the form: $database_table => array( value, ) */ @@ -2062,7 +2073,7 @@ class WC_Subscription extends WC_Order { $payment_gateway = isset( $payment_gateways[ $payment_method_id ] ) ? $payment_gateways[ $payment_method_id ] : null; } - if ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) { + if ( wcs_is_manual_renewal_required() ) { $this->set_requires_manual_renewal( true ); } elseif ( is_null( $payment_gateway ) || false == $payment_gateway->supports( 'subscriptions' ) ) { $this->set_requires_manual_renewal( true ); @@ -2081,8 +2092,12 @@ class WC_Subscription extends WC_Order { /** * Save payment method meta data for the Subscription * - * @since 2.0 - * @param array $payment_meta Associated array of the form: $database_table => array( value, ) + * @since 2.0.0 + * + * @throws InvalidArgumentException An exception if the payment meta variable isn't an array. + * + * @param string $payment_method_id The payment method's ID. + * @param array $payment_meta Associated array of the form: $database_table => array( value, ) */ protected function set_payment_method_meta( $payment_method_id, $payment_meta ) { @@ -2296,7 +2311,7 @@ class WC_Subscription extends WC_Order { */ public function get_item_downloads( $item ) { - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { wcs_deprecated_function( __METHOD__, '2.2.0', 'WC_Order_Item_Product::get_item_downloads(), because WooCommerce 3.0+ now uses that' ); } diff --git a/includes/class-wc-subscriptions-addresses.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php similarity index 76% rename from includes/class-wc-subscriptions-addresses.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php index f805e34..dd9bc35 100644 --- a/includes/class-wc-subscriptions-addresses.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-addresses.php @@ -21,6 +21,8 @@ class WC_Subscriptions_Addresses { add_filter( 'wcs_view_subscription_actions', __CLASS__ . '::add_edit_address_subscription_action', 10, 2 ); + add_action( 'template_redirect', array( __CLASS__, 'maybe_restrict_edit_address_endpoint' ) ); + add_action( 'woocommerce_after_edit_address_form_billing', __CLASS__ . '::maybe_add_edit_address_checkbox', 10 ); add_action( 'woocommerce_after_edit_address_form_shipping', __CLASS__ . '::maybe_add_edit_address_checkbox', 10 ); @@ -31,6 +33,21 @@ class WC_Subscriptions_Addresses { add_filter( 'woocommerce_get_breadcrumb', __CLASS__ . '::change_addresses_breadcrumb', 10, 1 ); } + /** + * Checks if a user can edit a subscription's address. + * + * @param int|WC_Subscription $subscription Post ID of a 'shop_subscription' post, or instance of a WC_Subscription object. + * @param int $user_id The ID of a user. + * @return bool Whether the user can edit the subscription's address. + * @since 3.0.15 + */ + private static function can_user_edit_subscription_address( $subscription, $user_id = 0 ) { + $subscription = wcs_get_subscription( $subscription ); + $user_id = empty( $user_id ) ? get_current_user_id() : absint( $user_id ); + + return $subscription ? user_can( $user_id, 'view_order', $subscription->get_id() ) : false; + } + /** * Add a "Change Shipping Address" button to the "My Subscriptions" table for those subscriptions * which require shipping. @@ -51,6 +68,23 @@ class WC_Subscriptions_Addresses { return $actions; } + /** + * Redirects to "My Account" when attempting to edit the address on a subscription that doesn't belong to the user. + * + * @since 3.0.15 + */ + public static function maybe_restrict_edit_address_endpoint() { + if ( ! is_wc_endpoint_url() || 'edit-address' !== WC()->query->get_current_endpoint() || ! isset( $_GET['subscription'] ) ) { + return; + } + + if ( ! self::can_user_edit_subscription_address( absint( $_GET['subscription'] ) ) ) { + wc_add_notice( 'Invalid subscription.', 'error' ); + wp_redirect( wc_get_account_endpoint_url( 'dashboard' ) ); + exit(); + } + } + /** * Outputs the necessary markup on the "My Account" > "Edit Address" page for editing a single subscription's * address or to check if the customer wants to update the addresses for all of their subscriptions. @@ -65,12 +99,13 @@ class WC_Subscriptions_Addresses { global $wp; if ( wcs_user_has_subscription() ) { + $subscription_id = isset( $_GET['subscription'] ) ? absint( $_GET['subscription'] ) : 0; - if ( isset( $_GET['subscription'] ) ) { + if ( $subscription_id && self::can_user_edit_subscription_address( $subscription_id ) ) { echo '

    ' . esc_html__( 'Both the shipping address used for the subscription and your default shipping address for future purchases will be updated.', 'woocommerce-subscriptions' ) . '

    '; - echo ''; + echo ''; } elseif ( ( ( isset( $wp->query_vars['edit-address'] ) && ! empty( $wp->query_vars['edit-address'] ) ) || isset( $_GET['address'] ) ) ) { @@ -81,7 +116,7 @@ class WC_Subscriptions_Addresses { } // translators: $1: address type (Shipping Address / Billing Address), $2: opening tag, $3: closing tag - $label = sprintf( esc_html__( 'Update the %1$s used for %2$sall%3$s of my active subscriptions', 'woocommerce-subscriptions' ), wcs_get_address_type_to_display( $address_type ), '', '' ); + $label = sprintf( esc_html__( 'Update the %1$s used for %2$sall%3$s future renewals of my active subscriptions', 'woocommerce-subscriptions' ), wcs_get_address_type_to_display( $address_type ), '', '' ); woocommerce_form_field( 'update_all_subscriptions_addresses', @@ -134,15 +169,15 @@ class WC_Subscriptions_Addresses { } } elseif ( isset( $_POST['update_subscription_address'] ) ) { - $subscription = wcs_get_subscription( intval( $_POST['update_subscription_address'] ) ); + $subscription = wcs_get_subscription( absint( $_POST['update_subscription_address'] ) ); - // Update the address only if the user actually owns the subscription - if ( ! empty( $subscription ) ) { + if ( $subscription && self::can_user_edit_subscription_address( $subscription->get_id() ) ) { + // Update the address only if the user actually owns the subscription $subscription->set_address( $address, $address_type ); - } - wp_safe_redirect( $subscription->get_view_order_url() ); - exit(); + wp_safe_redirect( $subscription->get_view_order_url() ); + exit(); + } } } @@ -153,9 +188,10 @@ class WC_Subscriptions_Addresses { * @since 1.5 */ public static function maybe_populate_subscription_addresses( $address ) { + $subscription_id = isset( $_GET['subscription'] ) ? absint( $_GET['subscription'] ) : 0; - if ( isset( $_GET['subscription'] ) ) { - $subscription = wcs_get_subscription( absint( $_GET['subscription'] ) ); + if ( $subscription_id && self::can_user_edit_subscription_address( $subscription_id ) ) { + $subscription = wcs_get_subscription( $subscription_id ); foreach ( array_keys( $address ) as $key ) { diff --git a/includes/class-wc-subscriptions-cart-validator.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php similarity index 79% rename from includes/class-wc-subscriptions-cart-validator.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php index 7fbf292..f158eff 100644 --- a/includes/class-wc-subscriptions-cart-validator.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php @@ -31,11 +31,11 @@ class WC_Subscriptions_Cart_Validator { * @since 2.6.0 */ public static function maybe_empty_cart( $valid, $product_id, $quantity, $variation_id = '', $variations = array() ) { - $is_subscription = WC_Subscriptions_Product::is_subscription( $product_id ); $cart_contains_subscription = WC_Subscriptions_Cart::cart_contains_subscription(); - $multiple_subscriptions_possible = WC_Subscriptions_Payment_Gateways::one_gateway_supports( 'multiple_subscriptions' ); - $manual_renewals_enabled = ( 'yes' === get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ) ); + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); + $multiple_subscriptions_possible = $payment_gateways_handler::one_gateway_supports( 'multiple_subscriptions' ); + $manual_renewals_enabled = wcs_is_manual_renewal_enabled(); $canonical_product_id = ! empty( $variation_id ) ? $variation_id : $product_id; if ( $is_subscription && 'yes' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { @@ -68,11 +68,7 @@ class WC_Subscriptions_Cart_Validator { wc_add_notice( __( 'A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); // Redirect to cart page to remove subscription & notify shopper - if ( WC_Subscriptions::is_woocommerce_pre( '3.0.8' ) ) { - add_filter( 'add_to_cart_fragments', 'WC_Subscriptions::redirect_ajax_add_to_cart' ); - } else { - add_filter( 'woocommerce_add_to_cart_fragments', 'WC_Subscriptions::redirect_ajax_add_to_cart' ); - } + add_filter( 'woocommerce_add_to_cart_fragments', array( __CLASS__, 'redirect_ajax_add_to_cart' ) ); } return $valid; @@ -111,11 +107,7 @@ class WC_Subscriptions_Cart_Validator { wc_add_notice( __( 'Your cart has been emptied of subscription products. Only one subscription product can be purchased at a time.', 'woocommerce-subscriptions' ), 'notice' ); // Redirect to cart page to remove subscription & notify shopper - if ( WC_Subscriptions::is_woocommerce_pre( '3.0.8' ) ) { - add_filter( 'add_to_cart_fragments', array( 'WC_Subscriptions', 'redirect_ajax_add_to_cart' ) ); - } else { - add_filter( 'woocommerce_add_to_cart_fragments', array( 'WC_Subscriptions', 'redirect_ajax_add_to_cart' ) ); - } + add_filter( 'woocommerce_add_to_cart_fragments', array( __CLASS__, 'redirect_ajax_add_to_cart' ) ); break; } @@ -140,4 +132,28 @@ class WC_Subscriptions_Cart_Validator { return $can_add; } + /** + * Adds the required cart AJAX args and filter callbacks to cause an error and redirect the customer. + * + * Attached by @see WC_Subscriptions_Cart_Validator::validate_cart_contents_for_mixed_checkout() and + * @see WC_Subscriptions_Cart_Validator::maybe_empty_cart() when the store has multiple subscription + * purcahses disabled, the cart already contains products and the customer adds a new item or logs in + * causing a cart merge. + * + * @since 4.0.0 + * + * @param array $fragments The add to cart AJAX args. + * @return array $fragments + */ + public static function add_to_cart_ajax_redirect( $fragments ) { + $fragments['error'] = true; + $fragments['product_url'] = wc_get_cart_url(); + + # Force error on add_to_cart() to redirect + add_filter( 'woocommerce_add_to_cart_validation', '__return_false', 10 ); + add_filter( 'woocommerce_cart_redirect_after_error', 'wc_get_cart_url', 10, 2 ); + do_action( 'wc_ajax_add_to_cart' ); + + return $fragments; + } } diff --git a/includes/class-wc-subscriptions-cart.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php similarity index 80% rename from includes/class-wc-subscriptions-cart.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php index 8ae18fd..a2bd0f6 100644 --- a/includes/class-wc-subscriptions-cart.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php @@ -60,7 +60,6 @@ class WC_Subscriptions_Cart { * @since 1.0 */ public static function init() { - // Make sure WC calculates total on sign up fee + price per period, and keep a record of the price per period add_action( 'woocommerce_before_calculate_totals', __CLASS__ . '::add_calculation_price_filter', 10 ); add_action( 'woocommerce_calculate_totals', __CLASS__ . '::remove_calculation_price_filter', 10 ); @@ -88,14 +87,12 @@ class WC_Subscriptions_Cart { add_action( 'woocommerce_review_order_after_order_total', __CLASS__ . '::display_recurring_totals' ); add_filter( 'woocommerce_cart_needs_shipping', __CLASS__ . '::cart_needs_shipping', 11, 1 ); + add_filter( 'woocommerce_cart_needs_shipping_address', __CLASS__ . '::cart_needs_shipping_address', 11, 1 ); // Remove recurring shipping methods stored in the session whenever a subscription product is removed from the cart add_action( 'woocommerce_remove_cart_item', array( __CLASS__, 'maybe_reset_chosen_shipping_methods' ) ); wcs_add_woocommerce_dependent_action( 'woocommerce_before_cart_item_quantity_zero', array( __CLASS__, 'maybe_reset_chosen_shipping_methods' ), '3.7.0', '<' ); - // Massage our shipping methods into the format used by WC core (we can't use normal form elements to do this as WC overrides them) - add_action( 'woocommerce_checkout_update_order_review', array( __CLASS__, 'add_shipping_method_post_data' ) ); - // Make sure we use our recurring shipping method for recurring shipping calculations not the default method add_filter( 'woocommerce_shipping_chosen_method', array( __CLASS__, 'set_chosen_shipping_method' ), 10, 2 ); @@ -103,7 +100,7 @@ class WC_Subscriptions_Cart { add_filter( 'woocommerce_package_rates', __CLASS__ . '::cache_package_rates', 1, 2 ); // When WooCommerce calculates rates for a recurring shipping package, make sure there is a different set of rates - add_filter( 'woocommerce_shipping_packages', __CLASS__ . '::reset_shipping_method_counts', 1000, 1 ); + add_filter( 'woocommerce_shipping_package_name', __CLASS__ . '::change_initial_shipping_package_name', 1, 3 ); // When WooCommerce determines the taxable address only return pick up shipping methods chosen for the recurring cart being calculated. add_filter( 'woocommerce_local_pickup_methods', __CLASS__ . '::filter_recurring_cart_chosen_shipping_method', 100, 1 ); @@ -118,6 +115,14 @@ class WC_Subscriptions_Cart { add_action( 'woocommerce_checkout_update_order_review', __CLASS__ . '::update_chosen_shipping_methods' ); add_action( 'plugins_loaded', array( __CLASS__, 'attach_dependant_hooks' ) ); + + add_action( 'woocommerce_after_calculate_totals', array( __CLASS__, 'record_base_tax_rates' ) ); + + // Add Subscriptions data to cart items. + add_filter( 'woocommerce_get_item_data', __CLASS__ . '::woocommerce_get_item_data', 10, 2 ); + + // Redirect the user immediately to the checkout page after clicking "Sign Up Now" buttons to encourage immediate checkout + add_filter( 'woocommerce_add_to_cart_redirect', array( __CLASS__, 'add_to_cart_redirect' ) ); } /** @@ -127,7 +132,7 @@ class WC_Subscriptions_Cart { */ public static function attach_dependant_hooks() { // WooCommerce determines if free shipping is available using the WC->cart total and coupons, we need to recalculate its availability when obtaining shipping methods for a recurring cart - if ( WC_Subscriptions::is_woocommerce_pre( '3.2' ) ) { + if ( wcs_is_woocommerce_pre( '3.2' ) ) { add_filter( 'woocommerce_shipping_free_shipping_is_available', array( __CLASS__, 'maybe_recalculate_shipping_method_availability' ), 10, 2 ); } else { add_filter( 'woocommerce_shipping_free_shipping_is_available', array( __CLASS__, 'recalculate_shipping_method_availability' ), 10, 3 ); @@ -143,7 +148,6 @@ class WC_Subscriptions_Cart { * @since 1.2 */ public static function add_calculation_price_filter() { - WC()->cart->recurring_carts = array(); // Only hook when cart contains a subscription @@ -152,12 +156,8 @@ class WC_Subscriptions_Cart { } // Set which price should be used for calculation - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - add_filter( 'woocommerce_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100, 2 ); - } else { - add_filter( 'woocommerce_product_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100, 2 ); - add_filter( 'woocommerce_product_variation_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100, 2 ); - } + add_filter( 'woocommerce_product_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100, 2 ); + add_filter( 'woocommerce_product_variation_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100, 2 ); } /** @@ -167,12 +167,8 @@ class WC_Subscriptions_Cart { * @since 1.2 */ public static function remove_calculation_price_filter() { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - remove_filter( 'woocommerce_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100 ); - } else { - remove_filter( 'woocommerce_product_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100 ); - remove_filter( 'woocommerce_product_variation_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100 ); - } + remove_filter( 'woocommerce_product_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100 ); + remove_filter( 'woocommerce_product_variation_get_price', __CLASS__ . '::set_subscription_prices_for_calculation', 100 ); } /** @@ -224,7 +220,7 @@ class WC_Subscriptions_Cart { if ( $trial_length > 0 ) { $price = $sign_up_fee; } else { - $price += $sign_up_fee; + $price = (float) $price + $sign_up_fee; // Casting to float for php8 compatibility. } } // else $price = recurring amount already as WC_Product->get_price() returns subscription price @@ -257,7 +253,6 @@ class WC_Subscriptions_Cart { * @version 2.0 */ public static function calculate_subscription_totals( $total, $cart ) { - if ( ! self::cart_contains_subscription() && ! wcs_cart_contains_resubscribe() ) { // cart doesn't contain subscription return $total; } elseif ( 'none' != self::$calculation_type ) { // We're in the middle of a recalculation, let it run @@ -273,7 +268,6 @@ class WC_Subscriptions_Cart { // Group the subscription items by their cart item key based on billing schedule foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) ) { $subscription_groups[ self::get_recurring_cart_key( $cart_item ) ][] = $cart_item_key; } @@ -285,7 +279,6 @@ class WC_Subscriptions_Cart { // Back up the shipping method. Chances are WC is going to wipe the chosen_shipping_methods data WC()->session->set( 'wcs_shipping_methods', WC()->session->get( 'chosen_shipping_methods', array() ) ); - WC()->session->set( 'wcs_shipping_method_counts', WC()->session->get( 'shipping_method_counts', array() ) ); // Now let's calculate the totals for each group of subscriptions self::$calculation_type = 'recurring_total'; @@ -296,11 +289,13 @@ class WC_Subscriptions_Cart { $recurring_cart = clone WC()->cart; $product = null; - self::$recurring_cart_key = $recurring_cart->recurring_cart_key = $recurring_cart_key; + // Set the current recurring key flag on this class, and store the recurring_cart_key to the new cart instance. + self::$recurring_cart_key = $recurring_cart_key; + $recurring_cart->recurring_cart_key = $recurring_cart_key; // Remove any items not in this subscription group foreach ( $recurring_cart->get_cart() as $cart_item_key => $cart_item ) { - if ( ! in_array( $cart_item_key, $subscription_group ) ) { + if ( ! in_array( $cart_item_key, $subscription_group, true ) ) { unset( $recurring_cart->cart_contents[ $cart_item_key ] ); continue; } @@ -316,7 +311,7 @@ class WC_Subscriptions_Cart { $recurring_cart->end_date = apply_filters( 'wcs_recurring_cart_end_date', WC_Subscriptions_Product::get_expiration_date( $product, $recurring_cart->start_date ), $recurring_cart, $product ); // Before calculating recurring cart totals, store this recurring cart object - self::$cached_recurring_cart = $recurring_cart; + self::set_cached_recurring_cart( $recurring_cart ); // No fees recur (yet) if ( is_callable( array( $recurring_cart, 'fees_api' ) ) ) { // WC 3.2 + @@ -326,7 +321,6 @@ class WC_Subscriptions_Cart { } $recurring_cart->fee_total = 0; - WC()->shipping->reset_shipping(); self::maybe_restore_shipping_methods(); $recurring_cart->calculate_totals(); @@ -341,10 +335,10 @@ class WC_Subscriptions_Cart { self::$recurring_shipping_packages[ $recurring_cart_key ] = WC()->shipping->get_packages(); } + // Reset flags when we're done processing recurring carts. self::$calculation_type = self::$recurring_cart_key = 'none'; // We need to reset the packages and totals stored in WC()->shipping too - WC()->shipping->reset_shipping(); self::maybe_restore_shipping_methods(); // Only calculate the initial order cart shipping if we need to show shipping. @@ -354,7 +348,6 @@ class WC_Subscriptions_Cart { // We no longer need our backup of shipping methods unset( WC()->session->wcs_shipping_methods ); - unset( WC()->session->shipping_method_counts ); // If there is no sign-up fee and a free trial, and no products being purchased with the subscription, we need to zero the fees for the first billing period $remove_fees_from_cart = ( 0 == self::get_cart_subscription_sign_up_fee() && self::all_cart_items_have_free_trial() ); @@ -370,7 +363,7 @@ class WC_Subscriptions_Cart { if ( apply_filters( 'wcs_remove_fees_from_initial_cart', $remove_fees_from_cart, $cart, $recurring_carts ) ) { $cart_fees = WC()->cart->get_fees(); - if ( WC_Subscriptions::is_woocommerce_pre( '3.2' ) ) { + if ( wcs_is_woocommerce_pre( '3.2' ) ) { foreach ( $cart_fees as $fee_index => $fee ) { WC()->cart->fees[ $fee_index ]->amount = 0; WC()->cart->fees[ $fee_index ]->tax = 0; @@ -407,59 +400,59 @@ class WC_Subscriptions_Cart { * When the cart contains a physical subscription with a free trial and no other physical items, shipping * should not be charged up-front. * + * @internal self::all_cart_items_have_free_trial() is false if non-subscription products are in the cart. + * * @since 1.5.4 */ public static function charge_shipping_up_front() { - - $charge_shipping_up_front = true; - - if ( self::all_cart_items_have_free_trial() ) { - - $charge_shipping_up_front = false; - $other_items_need_shipping = false; - - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( ! WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) && $cart_item['data']->needs_shipping() ) { - $other_items_need_shipping = true; - } - } - - if ( false === $other_items_need_shipping ) { - $charge_shipping_up_front = false; - } - } - - return apply_filters( 'woocommerce_subscriptions_cart_shipping_up_front', $charge_shipping_up_front ); + return apply_filters( 'woocommerce_subscriptions_cart_shipping_up_front', ! self::all_cart_items_have_free_trial() ); } /** * The cart needs shipping only if it needs shipping up front and/or for recurring items. * * @since 2.0 + * @param boolean $needs_shipping True if shipping is needed for the cart. + * @return boolean */ public static function cart_needs_shipping( $needs_shipping ) { if ( self::cart_contains_subscription() ) { - if ( 'none' == self::$calculation_type ) { - if ( true == $needs_shipping && ! self::charge_shipping_up_front() && ! self::cart_contains_subscriptions_needing_shipping() ) { - $needs_shipping = false; - } elseif ( false == $needs_shipping && ( self::charge_shipping_up_front() || self::cart_contains_subscriptions_needing_shipping() ) ) { - $needs_shipping = false; - } - } elseif ( 'recurring_total' == self::$calculation_type ) { - $cart = ( isset( self::$cached_recurring_cart ) ) ? self::$cached_recurring_cart : WC()->cart; + if ( 'none' === self::$calculation_type ) { + $has_subscription_needing_shipping = self::cart_contains_subscriptions_needing_shipping(); + $charge_shipping_up_front = self::charge_shipping_up_front(); - if ( true == $needs_shipping && ! self::cart_contains_subscriptions_needing_shipping( $cart ) ) { - $needs_shipping = false; - } elseif ( false == $needs_shipping && self::cart_contains_subscriptions_needing_shipping( $cart ) ) { + // If we have a subscription that either needs shipping, or needs shipping charging up front, force true. + if ( $has_subscription_needing_shipping && $charge_shipping_up_front ) { $needs_shipping = true; } + } elseif ( 'recurring_total' === self::$calculation_type ) { + $cart = isset( self::$cached_recurring_cart ) ? self::$cached_recurring_cart : WC()->cart; + $needs_shipping = self::cart_contains_subscriptions_needing_shipping( $cart ); } } return $needs_shipping; } + /** + * The cart needs a shipping address if any item needs shipping, including recurring items. + * + * @param boolean $needs_shipping_address True if a shipping address is needed for the cart. + * @return boolean + */ + public static function cart_needs_shipping_address( $needs_shipping_address ) { + if ( $needs_shipping_address ) { + return $needs_shipping_address; + } + + if ( ! wc_ship_to_billing_address_only() && self::cart_contains_subscription() ) { + $needs_shipping_address = self::cart_contains_subscriptions_needing_shipping(); + } + + return $needs_shipping_address; + } + /** * Remove all recurring shipping methods stored in the session (i.e. methods with a key that is a string) * @@ -487,100 +480,17 @@ class WC_Subscriptions_Cart { } /** - * Parse recurring shipping rates from the front end and put them into the $_POST['shipping_method'] used by WooCommerce. + * When shipping subscriptions, changes the original package to "initial shipment". * - * When WooCommerce takes the value of inputs for shipping methods selection from the cart and checkout pages, it uses a - * JavaScript array and therefore, can only use numerical indexes. This works for WC core, because it only needs shipping - * selection for different packages. However, we want to use string indexes to differentiate between different recurring - * cart shipping selection inputs *and* packages. To do this, we need to get our shipping methods from the $_POST['post_data'] - * values and manually add them $_POST['shipping_method'] array. - * - * We can't do this on the cart page unfortunately because it doesn't pass the entire forms post data and instead only - * sends the shipping methods with a numerical index. - * - * @return null - * @since 2.0.12 + * @param string $package_name Package name. + * @param string|int $package_id Package ID. + * @return array $package Package contents. */ - public static function add_shipping_method_post_data() { - - if ( ! WC_Subscriptions::is_woocommerce_pre( '2.6' ) ) { - return; + public static function change_initial_shipping_package_name( $package_name, $package_id, $package ) { + if ( ! self::cart_contains_subscription() || isset( $package['recurring_cart_key'] ) ) { + return $package_name; } - - check_ajax_referer( 'update-order-review', 'security' ); - - parse_str( $_POST['post_data'], $form_data ); - - // In case we have only free trials/sync'd products in the cart and shipping methods aren't being displayed - if ( ! isset( $_POST['shipping_method'] ) ) { - $_POST['shipping_method'] = array(); - } - if ( ! isset( $form_data['shipping_method'] ) ) { - $form_data['shipping_method'] = array(); - } - - foreach ( $form_data['shipping_method'] as $key => $methods ) { - if ( ! is_numeric( $key ) && ! array_key_exists( $key, $_POST['shipping_method'] ) ) { - $_POST['shipping_method'][ $key ] = $methods; - } - } - } - - /** - * When WooCommerce calculates rates for a recurring shipping package, we need to make sure there is a - * different number of rates to make sure WooCommerce updates the chosen method for the recurring cart - * and the 'woocommerce_shipping_chosen_method' filter is called, which we use to make sure the chosen - * method is the recurring method, not the initial method. - * - * This function is hooked to 'woocommerce_shipping_packages' called by WC_Shipping->calculate_shipping() - * which is why it accepts and returns the $packages array. It is also attached with a very high priority - * to avoid conflicts with any 3rd party plugins that may use the method count session value (only a couple - * of other hooks, including 'woocommerce_shipping_chosen_method' and 'woocommerce_shipping_method_chosen' - * are triggered between when this callback runs on 'woocommerce_shipping_packages' and when the session - * value is set again by WC_Shipping->calculate_shipping()). - * - * For more details, see: https://github.com/Prospress/woocommerce-subscriptions/pull/1187#issuecomment-186091152 - * - * @param array $packages An array of shipping package of the form returned by WC_Cart->get_shipping_packages() which includes the package's contents, cost, customer, destination and alternative rates - * @since 2.0.19 - */ - public static function reset_shipping_method_counts( $packages ) { - - if ( 'none' !== self::$recurring_cart_key ) { - WC()->session->set( 'shipping_method_counts', array() ); - } - - return $packages; - } - - /** - * Set the chosen shipping method for recurring cart calculations - * - * In WC_Shipping::calculate_shipping(), WooCommerce tries to determine the chosen shipping method - * based on the package index and stores rates. However, for recurring cart shipping selection, we - * use the recurring cart key instead of numeric index. Therefore, we need to hook in to override - * the default shipping method when WooCommerce could not find a matching shipping method. - * - * @param string $default_method the default shipping method for the customer/store returned by WC_Shipping::get_default_method() - * @param array $available_methods set of shipping rates for this calculation - * @param int $package_index WC doesn't pass the package index to callbacks on the 'woocommerce_shipping_chosen_method' filter (yet) so we set a default value of 0 for it in the function params - * @since 2.0.12 - */ - public static function set_chosen_shipping_method( $default_method, $available_methods, $package_index = 0 ) { - - $chosen_methods = WC()->session->get( 'chosen_shipping_methods', array() ); - - $recurring_cart_package_key = self::get_recurring_shipping_package_key( self::$recurring_cart_key, $package_index ); - - if ( 'none' !== self::$recurring_cart_key && isset( $chosen_methods[ $recurring_cart_package_key ] ) && isset( $available_methods[ $chosen_methods[ $recurring_cart_package_key ] ] ) ) { - $default_method = $chosen_methods[ $recurring_cart_package_key ]; - - // Set the chosen shipping method (if available) to workaround WC_Shipping::get_default_method() setting the default shipping method whenever method count changes - } elseif ( isset( $chosen_methods[ $package_index ] ) && $default_method !== $chosen_methods[ $package_index ] && isset( $available_methods[ $chosen_methods[ $package_index ] ] ) ) { - $default_method = $chosen_methods[ $package_index ]; - } - - return $default_method; + return __( 'Initial Shipment', 'woocommerce-subscriptions' ); } /** @@ -594,6 +504,15 @@ class WC_Subscriptions_Cart { return $recurring_cart_key . '_' . $package_index; } + /** + * Create a shipping package index for a given shipping package on a recurring cart. + * + * @return array + */ + public static function get_recurring_shipping_packages() { + return self::$recurring_shipping_packages; + } + /** * Add the shipping packages stored in @see self::$recurring_shipping_packages to WooCommerce's global * set of packages in WC()->shipping->packages so that plugins attempting to get the details of recurring @@ -604,7 +523,7 @@ class WC_Subscriptions_Cart { public static function set_global_recurring_shipping_packages() { foreach ( self::$recurring_shipping_packages as $recurring_cart_key => $packages ) { foreach ( $packages as $package_index => $package ) { - WC()->shipping->packages[ self::get_recurring_shipping_package_key( $recurring_cart_key, $package_index ) ] = $package; + WC()->shipping->packages[ $package_index ] = $package; } } } @@ -655,9 +574,16 @@ class WC_Subscriptions_Cart { if ( self::cart_contains_subscription() ) { foreach ( $cart->cart_contents as $cart_item_key => $values ) { $_product = $values['data']; - if ( WC_Subscriptions_Product::is_subscription( $_product ) && $_product->needs_shipping() && false === WC_Subscriptions_Product::needs_one_time_shipping( $_product ) ) { - $cart_contains_subscriptions_needing_shipping = true; + + if ( ! WC_Subscriptions_Product::is_subscription( $_product ) || ! $_product->needs_shipping() ) { + continue; } + + if ( 'recurring_total' === self::$calculation_type && WC_Subscriptions_Product::needs_one_time_shipping( $_product ) ) { + continue; + } + + $cart_contains_subscriptions_needing_shipping = true; } } @@ -671,37 +597,50 @@ class WC_Subscriptions_Cart { * @since 2.0 */ public static function set_cart_shipping_packages( $packages ) { + if ( ! self::cart_contains_subscription() ) { + return $packages; + } - if ( self::cart_contains_subscription() ) { - if ( 'none' == self::$calculation_type ) { - foreach ( $packages as $index => $package ) { - foreach ( $package['contents'] as $cart_item_key => $cart_item ) { - if ( WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) > 0 ) { - unset( $packages[ $index ]['contents'][ $cart_item_key ] ); - } - } - - if ( empty( $packages[ $index ]['contents'] ) ) { - unset( $packages[ $index ] ); + if ( 'none' === self::$calculation_type ) { + foreach ( $packages as $index => $package ) { + foreach ( $package['contents'] as $cart_item_key => $cart_item ) { + if ( WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) > 0 ) { + unset( $packages[ $index ]['contents'][ $cart_item_key ] ); } } - } elseif ( 'recurring_total' == self::$calculation_type ) { - foreach ( $packages as $index => $package ) { - foreach ( $package['contents'] as $cart_item_key => $cart_item ) { - if ( WC_Subscriptions_Product::needs_one_time_shipping( $cart_item['data'] ) ) { - $packages[ $index ]['contents_cost'] -= $cart_item['line_total']; - unset( $packages[ $index ]['contents'][ $cart_item_key ] ); - } - } - if ( empty( $packages[ $index ]['contents'] ) ) { - unset( $packages[ $index ] ); - } else { - // we need to make sure the package is different for recurring carts to bypass WC's cache - $packages[ $index ]['recurring_cart_key'] = self::$recurring_cart_key; - } + if ( empty( $packages[ $index ]['contents'] ) ) { + unset( $packages[ $index ] ); } } + } elseif ( 'recurring_total' === self::$calculation_type ) { + /** + * This logic runs for recurring carts, not the main cart. + */ + $new_packages = array(); + + foreach ( $packages as $index => $package ) { + $new_package = $package; + + // we need to make sure the package is different for recurring carts to bypass WC's cache + $new_package['recurring_cart_key'] = self::$recurring_cart_key; + + // We need to track the original package index. + $new_package['package_index'] = $index; + + foreach ( $new_package['contents'] as $cart_item_key => $cart_item ) { + if ( WC_Subscriptions_Product::needs_one_time_shipping( $cart_item['data'] ) ) { + $new_package['contents_cost'] -= $cart_item['line_total']; + unset( $new_package['contents'][ $cart_item_key ] ); + } + } + + if ( ! empty( $packages[ $index ]['contents'] ) ) { + $new_packages[ self::get_recurring_shipping_package_key( self::$recurring_cart_key, $index ) ] = $new_package; + } + } + + $packages = $new_packages; } return $packages; @@ -761,12 +700,7 @@ class WC_Subscriptions_Cart { public static function get_formatted_product_subtotal( $product_subtotal, $product, $quantity, $cart ) { if ( WC_Subscriptions_Product::is_subscription( $product ) && ! wcs_cart_contains_renewal() ) { - - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - $product_price_filter = 'woocommerce_get_price'; - } else { - $product_price_filter = is_a( $product, 'WC_Product_Variation' ) ? 'woocommerce_product_variation_get_price' : 'woocommerce_product_get_price'; - } + $product_price_filter = is_a( $product, 'WC_Product_Variation' ) ? 'woocommerce_product_variation_get_price' : 'woocommerce_product_get_price'; // Avoid infinite loop remove_filter( 'woocommerce_cart_product_subtotal', __CLASS__ . '::get_formatted_product_subtotal', 11 ); @@ -785,7 +719,7 @@ class WC_Subscriptions_Cart { array( 'price' => $product_subtotal, 'sign_up_fee' => $sign_up_fee_string, - 'tax_calculation' => WC_Subscriptions::is_woocommerce_pre( '4.4' ) ? WC()->cart->tax_display_cart : WC()->cart->get_tax_price_display_mode(), + 'tax_calculation' => wcs_is_woocommerce_pre( '4.4' ) ? WC()->cart->tax_display_cart : WC()->cart->get_tax_price_display_mode(), ) ); @@ -813,21 +747,17 @@ class WC_Subscriptions_Cart { * Checks the cart to see if it contains a subscription product. * * @since 1.0 + * @return boolean */ public static function cart_contains_subscription() { - - $contains_subscription = false; - if ( ! empty( WC()->cart->cart_contents ) && ! wcs_cart_contains_renewal() ) { foreach ( WC()->cart->cart_contents as $cart_item ) { if ( WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) ) { - $contains_subscription = true; - break; + return true; } } } - - return $contains_subscription; + return false; } /** @@ -851,17 +781,6 @@ class WC_Subscriptions_Cart { return $cart_contains_free_trial; } - /** - * Checks to see if payment method is required on a subscription product with a $0 initial payment. - * - * @since 2.5.0 - */ - public static function zero_initial_payment_requires_payment() { - - return 'yes' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_zero_initial_payment_requires_payment', 'no' ); - - } - /** * Gets the cart calculation type flag * @@ -877,12 +796,32 @@ class WC_Subscriptions_Cart { * @since 2.0 */ public static function set_calculation_type( $calculation_type ) { - self::$calculation_type = $calculation_type; - return $calculation_type; } + /** + * Sets the recurring cart key flag. + * + * @internal While this is indeed stored to the cart object, some hooks such as woocommerce_cart_shipping_packages + * do not have access to this property. So we can properly set package IDs we make use of this flag. + * + * @param string $recurring_cart_key Recurring cart key used to identify the current recurring cart being processed. + */ + public static function set_recurring_cart_key( $recurring_cart_key ) { + self::$recurring_cart_key = $recurring_cart_key; + return $recurring_cart_key; + } + + /** + * Update the cached recurring cart. + * + * @param \WC_Cart $recurring_cart Cart object. + */ + public static function set_cached_recurring_cart( $recurring_cart ) { + self::$cached_recurring_cart = $recurring_cart; + } + /** * Gets the subscription sign up fee for the cart and returns it * @@ -931,13 +870,13 @@ class WC_Subscriptions_Cart { return $needs_payment; } - // Skip checks if new $0 initial payments don't require a payment method or cart has no subscriptions. - if ( ! self::zero_initial_payment_requires_payment() || ! self::cart_contains_subscription() ) { + // Skip checks if cart has no subscriptions. + if ( ! self::cart_contains_subscription() ) { return $needs_payment; } // Skip checks if cart contains subscription switches or automatic payments are disabled. - if ( false !== WC_Subscriptions_Switcher::cart_contains_switches( 'any' ) || 'yes' === get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) { + if ( false !== wcs_cart_contains_switches( 'any' ) || wcs_is_manual_renewal_required() ) { return $needs_payment; } @@ -951,7 +890,7 @@ class WC_Subscriptions_Cart { $recurring_total += $recurring_cart->total; $subscription_length = wcs_cart_pluck( $recurring_cart, 'subscription_length' ); $contains_synced = $contains_synced || (bool) WC_Subscriptions_Synchroniser::cart_contains_synced_subscription( $recurring_cart ); - $contains_expiring_limited_coupon = $contains_expiring_limited_coupon || WC_Subscriptions_Coupon::recurring_cart_contains_expiring_coupon( $recurring_cart ); + $contains_expiring_limited_coupon = $contains_expiring_limited_coupon || ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) && WCS_Limited_Recurring_Coupon_Manager::recurring_cart_contains_expiring_coupon( $recurring_cart ) ); if ( 0 == $subscription_length || wcs_cart_pluck( $recurring_cart, 'subscription_period_interval' ) != $subscription_length ) { $is_one_period = false; @@ -979,11 +918,11 @@ class WC_Subscriptions_Cart { * @since 1.4.10 */ private static function maybe_restore_shipping_methods() { + WC()->shipping->reset_shipping(); + if ( ! empty( $_POST['calc_shipping'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) && function_exists( 'WC' ) ) { try { - WC()->shipping->reset_shipping(); - $country = wc_clean( $_POST['calc_shipping_country'] ); $state = isset( $_POST['calc_shipping_state'] ) ? wc_clean( $_POST['calc_shipping_state'] ) : ''; $postcode = apply_filters( 'woocommerce_shipping_calculator_enable_postcode', true ) ? wc_clean( $_POST['calc_shipping_postcode'] ) : ''; @@ -1038,7 +977,7 @@ class WC_Subscriptions_Cart { public static function cart_product_price( $price, $product ) { if ( WC_Subscriptions_Product::is_subscription( $product ) ) { - $tax_price_display_mode = WC_Subscriptions::is_woocommerce_pre( '4.4' ) ? WC()->cart->tax_display_cart : WC()->cart->get_tax_price_display_mode(); + $tax_price_display_mode = wcs_is_woocommerce_pre( '4.4' ) ? WC()->cart->tax_display_cart : WC()->cart->get_tax_price_display_mode(); $price = WC_Subscriptions_Product::get_price_string( $product, array( @@ -1061,31 +1000,26 @@ class WC_Subscriptions_Cart { if ( self::cart_contains_subscription() ) { // We only want shipping for recurring amounts, and they need to be calculated again here - self::$calculation_type = 'recurring_total'; - - $shipping_methods = array(); - + self::$calculation_type = 'recurring_total'; $carts_with_multiple_payments = 0; - // Create new subscriptions for each subscription product in the cart (that is not a renewal) - foreach ( WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart ) { - + foreach ( WC()->cart->recurring_carts as $recurring_cart ) { // Cart contains more than one payment if ( 0 != $recurring_cart->next_payment_date ) { $carts_with_multiple_payments++; } } - if ( $carts_with_multiple_payments >= 1 ) { + if ( apply_filters( 'woocommerce_subscriptions_display_recurring_totals', $carts_with_multiple_payments >= 1 ) ) { wc_get_template( 'checkout/recurring-totals.php', array( - 'shipping_methods' => $shipping_methods, + 'shipping_methods' => array(), 'recurring_carts' => WC()->cart->recurring_carts, 'carts_with_multiple_payments' => $carts_with_multiple_payments, ), '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' + WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } @@ -1166,7 +1100,7 @@ class WC_Subscriptions_Cart { */ public static function filter_recurring_cart_chosen_shipping_method( $shipping_methods ) { - if ( 'recurring_total' == self::$calculation_type && 'none' !== self::$recurring_cart_key ) { + if ( 'recurring_total' === self::$calculation_type && 'none' !== self::$recurring_cart_key ) { $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() ); @@ -1201,45 +1135,41 @@ class WC_Subscriptions_Cart { * @since 2.0.14 */ public static function validate_recurring_shipping_methods() { - $shipping_methods = WC()->checkout()->shipping_methods; $added_invalid_notice = false; $standard_packages = WC()->shipping->get_packages(); // temporarily store the current calculation type and recurring cart key so we can restore them later $calculation_type = self::$calculation_type; - self::$calculation_type = 'recurring_total'; $recurring_cart_key_flag = self::$recurring_cart_key; + self::set_calculation_type( 'recurring_total' ); + foreach ( WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart ) { + self::set_recurring_cart_key( $recurring_cart_key ); if ( false === $recurring_cart->needs_shipping() || 0 == $recurring_cart->next_payment_date ) { continue; } - self::$recurring_cart_key = $recurring_cart_key; + foreach ( $recurring_cart->get_shipping_packages() as $recurring_cart_package_key => $recurring_cart_package ) { + $package_index = isset( $recurring_cart_package['package_index'] ) ? $recurring_cart_package['package_index'] : 0; + $package = self::get_calculated_shipping_for_package( $recurring_cart_package ); - $packages = $recurring_cart->get_shipping_packages(); - - foreach ( $packages as $package_index => $base_package ) { - $package = self::get_calculated_shipping_for_package( $base_package ); - - if ( ( isset( $standard_packages[ $package_index ] ) && $package['rates'] == $standard_packages[ $package_index ]['rates'] ) && apply_filters( 'wcs_cart_totals_shipping_html_price_only', true, $package, WC()->cart->recurring_carts[ $recurring_cart_key ] ) ) { - // the recurring package rates match the initial package rates, there won't be a selected shipping method for this recurring cart package - // move on to the next package - continue; + if ( ( isset( $standard_packages[ $package_index ] ) && $package['rates'] == $standard_packages[ $package_index ]['rates'] ) ) { + // the recurring package rates match the initial package rates, there won't be a selected shipping method for this recurring cart package move on to the next package. + if ( apply_filters( 'wcs_cart_totals_shipping_html_price_only', true, $package, $recurring_cart ) ) { + continue; + } } - $recurring_shipping_package_key = self::get_recurring_shipping_package_key( $recurring_cart_key, $package_index ); - - if ( ! isset( $package['rates'][ $shipping_methods[ $recurring_shipping_package_key ] ] ) ) { - + if ( ! isset( $package['rates'][ $shipping_methods[ $recurring_cart_package_key ] ] ) ) { if ( ! $added_invalid_notice ) { wc_add_notice( __( 'Invalid recurring shipping method.', 'woocommerce-subscriptions' ), 'error' ); $added_invalid_notice = true; } - $shipping_methods[ $recurring_shipping_package_key ] = ''; + $shipping_methods[ $recurring_cart_package_key ] = ''; } } } @@ -1249,8 +1179,8 @@ class WC_Subscriptions_Cart { WC()->checkout()->shipping_methods = $shipping_methods; } - self::$calculation_type = $calculation_type; - self::$recurring_cart_key = $recurring_cart_key_flag; + self::set_calculation_type( $calculation_type ); + self::set_recurring_cart_key( $recurring_cart_key_flag ); } /** @@ -1266,7 +1196,7 @@ class WC_Subscriptions_Cart { if ( ! empty( WC()->cart->cart_contents ) ) { foreach ( WC()->cart->cart_contents as $cart_item ) { - if ( wcs_get_canonical_product_id( $cart_item ) == $product_id ) { + if ( wcs_get_canonical_product_id( $cart_item ) === $product_id ) { $cart_contains_product = true; break; } @@ -1363,7 +1293,7 @@ class WC_Subscriptions_Cart { return $is_available; } - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.2' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.2' ) ) { wcs_doing_it_wrong( __METHOD__, 'This method should no longer be used on WC 3.2.0 and newer. Use WC_Subscriptions_Cart::recalculate_shipping_method_availability() and pass the specific shipping method as the third parameter instead.', '2.5.6' ); } @@ -1487,6 +1417,116 @@ class WC_Subscriptions_Cart { } } + /** + * Records the cart item base location tax total for later storage. + * + * If the customer is outside of the base location, WC core removes the taxes + * which apply to the base location. @see WC_Cart_Totals::adjust_non_base_location_price(). + * + * We need to record these base tax rates to be able to honour grandfathered subscription + * recurring prices in renewal carts. + * + * @since 3.0.10 + * @param WC_Cart $cart The cart object. Could be the global (initial cart) or a recurring cart. + */ + public static function record_base_tax_rates( $cart ) { + // We only need to record the tax rates on recurring carts when prices are reduced by tax applicable to the base store location. + if ( ! isset( $cart->recurring_cart_key ) || ! apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) || ! wc_prices_include_tax() ) { + return; + } + + foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) { + // Skip non-taxable items + if ( 'taxable' !== $cart_item['data']->get_tax_status() ) { + continue; + } + + $product = $cart_item['data']; + + // Get the taxes which apply to the store's base location and to the customer. + $base_tax_rates = WC_Tax::get_base_tax_rates( $product->get_tax_class( 'unfiltered' ) ); + $applicable_tax_rates = WC_Tax::get_rates( $product->get_tax_class(), $cart->get_customer() ); + + // We only need to keep track if the taxes applicable to the customer are different to the taxes which apply to the store's base location. + if ( $applicable_tax_rates !== $base_tax_rates ) { + $cart->cart_contents[ $cart_item_key ]['_subtracted_base_location_taxes'] = WC_Tax::calc_tax( $product->get_price(), $base_tax_rates, true ); + $cart->cart_contents[ $cart_item_key ]['_subtracted_base_location_rates'] = $base_tax_rates; + } + } + } + + /** + * Set the chosen shipping method for recurring cart calculations + * + * In WC_Shipping::calculate_shipping(), WooCommerce tries to determine the chosen shipping method + * based on the package index and stores rates. However, for recurring cart shipping selection, we + * use the recurring cart key instead of numeric index. Therefore, we need to hook in to override + * the default shipping method when WooCommerce could not find a matching shipping method. + * + * @since 2.0.12 + * + * @param string $default_method the default shipping method for the customer/store returned by WC_Shipping::get_default_method() + * @param array $available_methods set of shipping rates for this calculation + * @param int $package_index WC doesn't pass the package index to callbacks on the 'woocommerce_shipping_chosen_method' filter (yet) so we set a default value of 0 for it in the function params + * + * @return $default_method + */ + public static function set_chosen_shipping_method( $default_method, $available_methods, $package_index = 0 ) { + $chosen_methods = WC()->session->get( 'chosen_shipping_methods', array() ); + $recurring_cart_package_key = self::get_recurring_shipping_package_key( self::$recurring_cart_key, $package_index ); + + if ( 'none' !== self::$recurring_cart_key && isset( $chosen_methods[ $recurring_cart_package_key ], $available_methods[ $chosen_methods[ $recurring_cart_package_key ] ] ) ) { + $default_method = $chosen_methods[ $recurring_cart_package_key ]; + + // Set the chosen shipping method (if available) to workaround WC_Shipping::get_default_method() setting the default shipping method whenever method count changes + } elseif ( isset( $chosen_methods[ $package_index ], $available_methods[ $chosen_methods[ $package_index ] ] ) && $default_method !== $chosen_methods[ $package_index ] ) { + $default_method = $chosen_methods[ $package_index ]; + } + + return $default_method; + } + + /** + * Redirects the customer to the cart after they add a subscription to the cart. + * + * Only enabled if multiple checkout is not enabled. + * + * @since 4.0.0 + * + * @param string $url The cart redirect $url. + * @return string $url. + */ + public static function add_to_cart_redirect( $url ) { + if ( ! isset( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) ) { + return $url; + } + + // If product is of the subscription type + if ( ! WC_Subscriptions_Product::is_subscription( absint( $_REQUEST['add-to-cart'] ) ) ) { + return $url; + } + + // Redirect to checkout if mixed checkout is disabled + if ( 'yes' === get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { + return $url; + } + + $quantity = isset( $_REQUEST['quantity'] ) ? $_REQUEST['quantity'] : 1; + $product_id = $_REQUEST['add-to-cart']; + + $add_to_cart_notice = wc_add_to_cart_message( array( $product_id => $quantity ), true, true ); + + if ( wc_has_notice( $add_to_cart_notice ) ) { + $notices = wc_get_notices(); + $add_to_cart_notice_index = array_search( $add_to_cart_notice, $notices['success'] ); + + unset( $notices['success'][ $add_to_cart_notice_index ] ); + wc_set_notices( $notices ); + } + + return wc_get_checkout_url(); + } + /* Deprecated */ /** @@ -2320,34 +2360,239 @@ class WC_Subscriptions_Cart { */ public static function maybe_restore_chosen_shipping_method() { $chosen_shipping_method_cache = WC()->session->get( 'wcs_shipping_methods', false ); - $shipping_method_counts_cache = WC()->session->get( 'wcs_shipping_method_counts', false ); - $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() ); - if ( false !== $chosen_shipping_method_cache && empty( $chosen_shipping_methods ) ) { + if ( false !== $chosen_shipping_method_cache ) { WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_method_cache ); - WC()->session->set( 'shipping_method_counts', $shipping_method_counts_cache ); } } + /** + * Return a localized free trial period string. + * + * @param int An interval in the range 1-6 + * @param string One of day, week, month or year. + */ + public static function format_free_trial_period( $number, $period ) { + if ( 'day' === $period ) { + // translators: placeholder is a number of days. + return sprintf( _n( '%s day', '%s days', $number, 'woocommerce-subscriptions' ), $number ); + } + if ( 'week' === $period ) { + // translators: placeholder is a number of weeks. + return sprintf( _n( '%s week', '%s weeks', $number, 'woocommerce-subscriptions' ), $number ); + } + if ( 'month' === $period ) { + // translators: placeholder is a number of months. + return sprintf( _n( '%s month', '%s months', $number, 'woocommerce-subscriptions' ), $number ); + } + if ( 'year' === $period ) { + // translators: placeholder is a number of years. + return sprintf( _n( '%s year', '%s years', $number, 'woocommerce-subscriptions' ), $number ); + } + return ''; + } + /** - * When WooCommerce calculates rates for a recurring shipping package, previously we would return both a different number - * of rates, and a unique set of rates for the recurring shipping package to make sure WooCommerce updated the - * chosen method for the recurring cart (and the 'woocommerce_shipping_chosen_method' filter was called, which - * we use to make sure the chosen method is the recurring method, not the initial method). + * Return a localized sync string, copied from WC_Subscriptions_Product::get_price_string * - * This is no longer necessary with the introductino of self::reset_shipping_method_counts() which achieves the same thing - * via a different means, while allowing WooCommerce's cached rates to be used and avoiding the issue reported in - * https://github.com/Prospress/woocommerce-subscriptions/issues/1583 + * @param WC_Product_Subscription $product The synced product. + * @param string $period One of day, week, month or year. + * @param int $interval An interval in the range 1-6 + * @return string The new sync string. + */ + public static function format_sync_period( $product, string $period, int $interval ) { + global $wp_locale; + $payment_day = WC_Subscriptions_Synchroniser::get_products_payment_day( $product ); + switch ( $period ) { + case 'week': + $payment_day_of_week = WC_Subscriptions_Synchroniser::get_weekday( $payment_day ); + if ( 1 === $interval ) { + // translators: 1$: day of the week (e.g. "every Wednesday"). + return sprintf( __( 'every %1$s', 'woocommerce-subscriptions' ), $payment_day_of_week ); + } else { + return sprintf( + // translators: 1$: period, 2$: day of the week (e.g. "every 2nd week on Wednesday"). + __( 'every %1$s on %2$s', 'woocommerce-subscriptions' ), + wcs_get_subscription_period_strings( $interval,$period ), + $payment_day_of_week + ); + } + break; + case 'month': + if ( 1 === $interval ) { + if ( $payment_day > 27 ) { + return __( 'on the last day of each month', 'woocommerce-subscriptions' ); + } else { + return sprintf( + // translators: 1$: day of the month (e.g. "23rd") (e.g. "every 23rd of each month"). + __( 'on the %1$s of each month', 'woocommerce-subscriptions' ), + wcs_append_numeral_suffix( $payment_day ) + ); + } + } else { + if ( $payment_day > 27 ) { + return sprintf( + // translators: 1$: interval (e.g. "3rd") (e.g. "on the last day of every 3rd month"). + __( 'on the last day of every %1$s month', 'woocommerce-subscriptions' ), + wcs_append_numeral_suffix( $interval ) + ); + } else { + return sprintf( + // translators: on the, 1$: day of every, 2$: month (e.g. "on the 23rd day of every 2nd month"). + __( 'on the %1$s day of every %2$s month', 'woocommerce-subscriptions' ), + wcs_append_numeral_suffix( $payment_day ), + wcs_append_numeral_suffix( $interval ) + ); + } + } + break; + case 'year': + if ( 1 === $interval ) { + return sprintf( + // translators: on, 1$: , 2$: each year (e.g. "on March 15th each year"). + __( 'on %1$s %2$s each year', 'woocommerce-subscriptions' ), + $wp_locale->month[ $payment_day['month'] ], + wcs_append_numeral_suffix( $payment_day['day'] ) + ); + } else { + return sprintf( + // translators: 1$: month (e.g. "March"), 2$: day of the month (e.g. "23rd), 3$: interval year (r.g March 23rd every 2nd year"). + __( 'on %1$s %2$s every %3$s year', 'woocommerce-subscriptions' ), + $wp_locale->month[ $payment_day['month'] ], + wcs_append_numeral_suffix( $payment_day['day'] ), + wcs_append_numeral_suffix( $interval ) + ); + } + break; + } + } + /** + * Adds meta data so it can be displayed in the Cart. + */ + public static function woocommerce_get_item_data( $other_data, $cart_item ) { + $product = $cart_item['data']; + + if ( ! WC_Subscriptions_Product::is_subscription( $product ) ) { + return $other_data; + } + + $trial_length = WC_Subscriptions_Product::get_trial_length( $product ); + if ( $trial_length ) { + $other_data[] = array( + 'name' => __( 'Free trial', 'woocommerce-subscriptions' ), + 'value' => self::format_free_trial_period( $trial_length, WC_Subscriptions_Product::get_trial_period( $product ) ), + 'hidden' => true, + '__experimental_woocommerce_blocks_hidden' => false, + ); + } + + $sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee( $product ); + if ( $sign_up_fee ) { + $other_data[] = array( + 'name' => __( 'Sign up fee', 'woocommerce-subscriptions' ), + 'value' => wc_price( $sign_up_fee ), + 'hidden' => true, + '__experimental_woocommerce_blocks_hidden' => false, + ); + } + + $synchronised_cart_item = WC_Subscriptions_Synchroniser::is_product_synced( $product ); + if ( $synchronised_cart_item ) { + $other_data[] = array( + 'name' => __( 'Renews', 'woocommerce-subscriptions' ), + 'value' => self::format_sync_period( $product, WC_Subscriptions_Product::get_period( $product ), WC_Subscriptions_Product::get_interval( $product ) ), + 'hidden' => true, + '__experimental_woocommerce_blocks_hidden' => false, + ); + } + + return $other_data; + } + + /** + * Parse recurring shipping rates from the front end and put them into the $_POST['shipping_method'] used by WooCommerce. * - * This function is hooked to 'woocommerce_package_rates' called by WC_Shipping->calculate_shipping_for_package() + * When WooCommerce takes the value of inputs for shipping methods selection from the cart and checkout pages, it uses a + * JavaScript array and therefore, can only use numerical indexes. This works for WC core, because it only needs shipping + * selection for different packages. However, we want to use string indexes to differentiate between different recurring + * cart shipping selection inputs *and* packages. To do this, we need to get our shipping methods from the $_POST['post_data'] + * values and manually add them $_POST['shipping_method'] array. * - * @param array $package_rates A set of shipping method objects in the form of WC_Shipping_Rate->id => WC_Shipping_Rate with the cost for that rate - * @param array $package A shipping package of the form returned by WC_Cart->get_shipping_packages() which includes the package's contents, cost, customer, destination and alternative rates + * We can't do this on the cart page unfortunately because it doesn't pass the entire forms post data and instead only + * sends the shipping methods with a numerical index. + * + * @deprecated 3.1.0 + * @return null * @since 2.0.12 */ - public static function filter_package_rates( $package_rates, $package ) { - _deprecated_function( __METHOD__, '2.0.19' ); - return $package_rates; + public static function add_shipping_method_post_data() { + wcs_deprecated_function( __METHOD__, '3.1.0' ); + if ( ! wcs_is_woocommerce_pre( '2.6' ) ) { + return; + } + + check_ajax_referer( 'update-order-review', 'security' ); + + parse_str( $_POST['post_data'], $form_data ); + + // In case we have only free trials/sync'd products in the cart and shipping methods aren't being displayed + if ( ! isset( $_POST['shipping_method'] ) ) { + $_POST['shipping_method'] = array(); + } + if ( ! isset( $form_data['shipping_method'] ) ) { + $form_data['shipping_method'] = array(); + } + + foreach ( $form_data['shipping_method'] as $key => $methods ) { + if ( ! is_numeric( $key ) && ! array_key_exists( $key, $_POST['shipping_method'] ) ) { + $_POST['shipping_method'][ $key ] = $methods; + } + } + } + + /** + * When WooCommerce calculates rates for a recurring shipping package, we need to make sure there is a + * different number of rates to make sure WooCommerce updates the chosen method for the recurring cart + * and the 'woocommerce_shipping_chosen_method' filter is called, which we use to make sure the chosen + * method is the recurring method, not the initial method. + * + * This function is hooked to 'woocommerce_shipping_packages' called by WC_Shipping->calculate_shipping() + * which is why it accepts and returns the $packages array. It is also attached with a very high priority + * to avoid conflicts with any 3rd party plugins that may use the method count session value (only a couple + * of other hooks, including 'woocommerce_shipping_chosen_method' and 'woocommerce_shipping_method_chosen' + * are triggered between when this callback runs on 'woocommerce_shipping_packages' and when the session + * value is set again by WC_Shipping->calculate_shipping()). + * + * For more details, see: https://github.com/Prospress/woocommerce-subscriptions/pull/1187#issuecomment-186091152 + * + * @deprecated 3.1.0 + * + * @param array $packages An array of shipping package of the form returned by WC_Cart->get_shipping_packages() which includes the package's contents, cost, customer, destination and alternative rates + * @since 2.0.19 + */ + public static function reset_shipping_method_counts( $packages ) { + wcs_deprecated_function( __METHOD__, '3.1.0' ); + if ( 'none' !== self::$recurring_cart_key ) { + WC()->session->set( 'shipping_method_counts', array() ); + } + + return $packages; + } + + /** + * Checks to see if payment method is required on a subscription product with a $0 initial payment. + * + * @since 2.5.0 + * @deprecated 4.0.0 + */ + public static function zero_initial_payment_requires_payment() { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Zero_Initial_Payment_Checkout_Manager::zero_initial_checkout_requires_payment() if available.' ); + + if ( class_exists( 'WCS_Zero_Initial_Payment_Checkout_Manager' ) ) { + return WCS_Zero_Initial_Payment_Checkout_Manager::zero_initial_checkout_requires_payment(); + } + + return true; } } diff --git a/includes/class-wc-subscriptions-change-payment-gateway.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php similarity index 89% rename from includes/class-wc-subscriptions-change-payment-gateway.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php index 20bf7ec..d10cf5f 100644 --- a/includes/class-wc-subscriptions-change-payment-gateway.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-change-payment-gateway.php @@ -29,8 +29,8 @@ class WC_Subscriptions_Change_Payment_Gateway { // Maybe allow for a recurring payment method to be changed add_action( 'plugins_loaded', __CLASS__ . '::set_change_payment_method_flag' ); - // Attach hooks which depend on WooCommerce constants - add_action( 'woocommerce_loaded', __CLASS__ . '::attach_dependant_hooks' ); + // If we're changing the payment method, we want to make sure a number of totals return $0 (to prevent payments being processed now) + add_filter( 'woocommerce_subscription_get_total', __CLASS__ . '::maybe_zero_total', 11, 2 ); // Keep a record of any messages or errors that should be displayed add_action( 'before_woocommerce_pay', __CLASS__ . '::store_pay_shortcode_messages', 5 ); @@ -74,26 +74,6 @@ class WC_Subscriptions_Change_Payment_Gateway { } - /** - * Attach WooCommerce version dependent hooks - * - * @since 2.2.0 - */ - public static function attach_dependant_hooks() { - - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - - // If we're changing the payment method, we want to make sure a number of totals return $0 (to prevent payments being processed now) - add_filter( 'woocommerce_order_amount_total', __CLASS__ . '::maybe_zero_total', 11, 2 ); - - } else { - - // If we're changing the payment method, we want to make sure a number of totals return $0 (to prevent payments being processed now) - add_filter( 'woocommerce_subscription_get_total', __CLASS__ . '::maybe_zero_total', 11, 2 ); - - } - } - /** * Set a flag to indicate that the current request is for changing payment. Better than requiring other extensions * to check the $_GET global as it allows for the flag to be overridden. @@ -185,7 +165,7 @@ class WC_Subscriptions_Change_Payment_Gateway { // Re-add all the notices that would have been displayed but have now been cleared from the output. foreach ( self::$notices as $notice_type => $notices ) { foreach ( $notices as $notice ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.9' ) ) { + if ( wcs_is_woocommerce_pre( '3.9' ) ) { wc_add_notice( $notice, $notice_type ); } else { wc_add_notice( $notice['notice'], $notice_type, $notice['data'] ); @@ -208,7 +188,7 @@ class WC_Subscriptions_Change_Payment_Gateway { } // translators: placeholder is either empty or "Next payment is due..." - wc_print_notice( sprintf( __( 'Choose a new payment method.%s', 'woocommerce-subscriptions' ), $next_payment_string ), 'notice' ); + wc_print_notice( apply_filters( 'woocommerce_subscriptions_change_payment_method_page_notice_message', sprintf( __( 'Choose a new payment method.%s', 'woocommerce-subscriptions' ), $next_payment_string ), $subscription ), 'notice' ); // Set the customer location to subscription billing location foreach ( array( 'country', 'state', 'postcode' ) as $address_property ) { @@ -219,7 +199,7 @@ class WC_Subscriptions_Change_Payment_Gateway { } } - wc_get_template( 'checkout/form-change-payment-method.php', array( 'subscription' => $subscription ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); + wc_get_template( 'checkout/form-change-payment-method.php', array( 'subscription' => $subscription ), '', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } } @@ -499,11 +479,12 @@ class WC_Subscriptions_Change_Payment_Gateway { $old_payment_method = $subscription->get_payment_method(); $old_payment_method_title = $subscription->get_payment_method_title(); $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); // Also inits all payment gateways to make sure that hooks are attached correctly + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); do_action( 'woocommerce_subscriptions_pre_update_payment_method', $subscription, $new_payment_method, $old_payment_method ); // Make sure the subscription is cancelled with the current gateway - WC_Subscriptions_Payment_Gateways::trigger_gateway_status_updated_hook( $subscription, 'cancelled' ); + $payment_gateways_handler::trigger_gateway_status_updated_hook( $subscription, 'cancelled' ); // Update meta if ( isset( $available_gateways[ $new_payment_method ] ) ) { @@ -520,21 +501,47 @@ class WC_Subscriptions_Change_Payment_Gateway { $new_payment_method_title = $new_payment_method; } - $subscription->update_meta_data( '_old_payment_method', $old_payment_method ); - $subscription->update_meta_data( '_old_payment_method_title', $old_payment_method_title ); - $subscription->set_payment_method( $new_payment_method, $new_payment_method_meta ); - $subscription->set_payment_method_title( $new_payment_method_title ); + // Changing the payment method can throw an exception via set_payment_method() -> set_payment_method_meta(). Catch it and display an error. + try { + $subscription->set_payment_method( $new_payment_method, $new_payment_method_meta ); + $subscription->set_payment_method_title( $new_payment_method_title ); + $subscription->update_meta_data( '_old_payment_method', $old_payment_method ); + $subscription->update_meta_data( '_old_payment_method_title', $old_payment_method_title ); - // Log change on order - // translators: 1: old payment title, 2: new payment title. - $subscription->add_order_note( sprintf( _x( 'Payment method changed from "%1$s" to "%2$s" by the subscriber from their account page.', '%1$s: old payment title, %2$s: new payment title', 'woocommerce-subscriptions' ), $old_payment_method_title, $new_payment_method_title ) ); + // Allow third-parties to filter the payment method titles used in the subscription note. + $old_payment_method_title = (string) apply_filters( 'woocommerce_subscription_note_old_payment_method_title', $old_payment_method_title, $old_payment_method, $subscription ); + $new_payment_method_title = (string) apply_filters( 'woocommerce_subscription_note_new_payment_method_title', $new_payment_method_title, $new_payment_method, $subscription ); - $subscription->save(); + // Log change on order + // translators: 1: old payment title, 2: new payment title. + $subscription->add_order_note( sprintf( _x( 'Payment method changed from "%1$s" to "%2$s" by the subscriber.', '%1$s: old payment title, %2$s: new payment title', 'woocommerce-subscriptions' ), $old_payment_method_title, $new_payment_method_title ) ); - do_action( 'woocommerce_subscription_payment_method_updated', $subscription, $new_payment_method, $old_payment_method ); - do_action( 'woocommerce_subscription_payment_method_updated_to_' . $new_payment_method, $subscription, $old_payment_method ); - if ( $old_payment_method ) { - do_action( 'woocommerce_subscription_payment_method_updated_from_' . $old_payment_method, $subscription, $new_payment_method ); + $subscription->save(); + + do_action( 'woocommerce_subscription_payment_method_updated', $subscription, $new_payment_method, $old_payment_method ); + do_action( 'woocommerce_subscription_payment_method_updated_to_' . $new_payment_method, $subscription, $old_payment_method ); + + if ( $old_payment_method ) { + do_action( 'woocommerce_subscription_payment_method_updated_from_' . $old_payment_method, $subscription, $new_payment_method ); + } + } catch ( Exception $e ) { + $message = __( "An error occurred updating your subscription's payment method. Please contact us for assistance.", 'woocommerce-subscriptions' ); + + if ( ! wc_has_notice( $message, 'error' ) ) { + wc_add_notice( $message, 'error' ); + } + + // Add an error notice specific to this error if it hasn't been added yet. This will generate the unique list of errors which occured. + $error_message = sprintf( + __( '%1$sError:%2$s %3$s', 'woocommerce-subscriptions' ), + '', + '', + $e->getMessage() + ); + + if ( ! wc_has_notice( $error_message, 'error' ) ) { + wc_add_notice( $error_message, 'error' ); + } } } @@ -653,7 +660,7 @@ class WC_Subscriptions_Change_Payment_Gateway { public static function can_subscription_be_updated_to_new_payment_method( $subscription_can_be_changed, $subscription ) { // Don't allow if automatic payments are disabled and the toggle is also disabled. - if ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) && ! WCS_My_Account_Auto_Renew_Toggle::is_enabled() ) { + if ( wcs_is_manual_renewal_required() && ! WCS_My_Account_Auto_Renew_Toggle::is_enabled() ) { return false; } @@ -663,7 +670,8 @@ class WC_Subscriptions_Change_Payment_Gateway { } // Don't allow if no gateways support changing methods. - if ( ! WC_Subscriptions_Payment_Gateways::one_gateway_supports( 'subscription_payment_method_change_customer' ) ) { + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); + if ( ! $payment_gateways_handler::one_gateway_supports( 'subscription_payment_method_change_customer' ) ) { return false; } @@ -701,13 +709,7 @@ class WC_Subscriptions_Change_Payment_Gateway { return $title; } - if ( $subscription->has_payment_gateway() ) { - $title = _x( 'Change payment method', 'the page title of the change payment method form', 'woocommerce-subscriptions' ); - } else { - $title = _x( 'Add payment method', 'the page title of the add payment method form', 'woocommerce-subscriptions' ); - } - - return $title; + return self::get_change_payment_method_page_title( $subscription ); } /** @@ -738,22 +740,32 @@ class WC_Subscriptions_Change_Payment_Gateway { esc_url( $subscription->get_view_order_url() ), ); - if ( $subscription->has_payment_gateway() ) { - $crumbs[3] = array( - _x( 'Change payment method', 'the page title of the change payment method form', 'woocommerce-subscriptions' ), - '', - ); - } else { - $crumbs[3] = array( - _x( 'Add payment method', 'the page title of the add payment method form', 'woocommerce-subscriptions' ), - '', - ); - } + $crumbs[3] = array( + self::get_change_payment_method_page_title( $subscription ), + '', + ); } return $crumbs; } + /** + * Get the Change Payment Method page title (also used for the page breadcrumb) + * + * @since 4.0.0 + * @param WC_Subscription $subscription + * @return string + */ + public static function get_change_payment_method_page_title( $subscription ) { + if ( $subscription->has_payment_gateway() ) { + $title = _x( 'Change payment method', 'the page title of the change payment method form', 'woocommerce-subscriptions' ); + } else { + $title = _x( 'Add payment method', 'the page title of the add payment method form', 'woocommerce-subscriptions' ); + } + + return apply_filters( 'woocommerce_subscriptions_change_payment_method_page_title', $title, $subscription ); + } + /** * When processing a change_payment_method request on a subscription that has a failed or pending renewal, * we don't want the `$order->needs_payment()` check inside WC_Shortcode_Checkout::order_pay() to pass. @@ -869,4 +881,23 @@ class WC_Subscriptions_Change_Payment_Gateway { return $subscription_can_be_changed; } + + /** + * Attach WooCommerce version dependent hooks + * + * @since 1.0.0 + * + * @deprecated 1.6.4 + */ + public static function attach_dependant_hooks() { + _deprecated_function( __METHOD__, '1.6.4' ); + + if ( wcs_is_woocommerce_pre( '3.0' ) ) { + // If we're changing the payment method, we want to make sure a number of totals return $0 (to prevent payments being processed now) + add_filter( 'woocommerce_order_amount_total', __CLASS__ . '::maybe_zero_total', 11, 2 ); + } else { + // If we're changing the payment method, we want to make sure a number of totals return $0 (to prevent payments being processed now) + add_filter( 'woocommerce_subscription_get_total', __CLASS__ . '::maybe_zero_total', 11, 2 ); + } + } } diff --git a/includes/class-wc-subscriptions-checkout.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php similarity index 65% rename from includes/class-wc-subscriptions-checkout.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php index 213a3b0..5cd9784 100644 --- a/includes/class-wc-subscriptions-checkout.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php @@ -23,26 +23,32 @@ class WC_Subscriptions_Checkout { // We need to create subscriptions on checkout and want to do it after almost all other extensions have added their products/items/fees add_action( 'woocommerce_checkout_order_processed', array( __CLASS__, 'process_checkout' ), 100, 2 ); - // Make sure users can register on checkout (before any other hooks before checkout) - add_action( 'woocommerce_before_checkout_form', array( __CLASS__, 'make_checkout_registration_possible' ), -1 ); - - // Display account fields as required - add_action( 'woocommerce_checkout_fields', array( __CLASS__, 'make_checkout_account_fields_required' ), 10 ); - - // Restore the settings after switching them for the checkout form - add_action( 'woocommerce_after_checkout_form', array( __CLASS__, 'restore_checkout_registration_settings' ), 100 ); + // Same as above, but this is for the Checkout block. + if ( class_exists( 'Automattic\WooCommerce\Blocks\Package' ) && ( version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '6.3.0', '>=' ) || \Automattic\WooCommerce\Blocks\Package::is_experimental_build() ) ) { + add_action( 'woocommerce_blocks_checkout_order_processed', array( __CLASS__, 'process_checkout' ), 100, 1 ); + } else { + add_action( '__experimental_woocommerce_blocks_checkout_order_processed', array( __CLASS__, 'process_checkout' ), 100, 1 ); + } // Some callbacks need to hooked after WC has loaded. add_action( 'woocommerce_loaded', array( __CLASS__, 'attach_dependant_hooks' ) ); - // Force registration during checkout process - add_action( 'woocommerce_before_checkout_process', array( __CLASS__, 'force_registration_during_checkout' ), 10 ); - // When a line item is added to a subscription on checkout, ensure the backorder data added by WC is removed add_action( 'woocommerce_checkout_create_order_line_item', array( __CLASS__, 'remove_backorder_meta_from_subscription_line_item' ), 10, 4 ); // When a line item is added to a subscription, ensure the __has_trial meta data is added if applicable. add_action( 'woocommerce_checkout_create_order_line_item', array( __CLASS__, 'maybe_add_free_trial_item_meta' ), 10, 4 ); + + // Store the amount of tax removed from a line item to account the base location's tax. + add_action( 'woocommerce_checkout_create_order_line_item', array( __CLASS__, 'store_line_item_base_location_taxes' ), 10, 3 ); + + // Make sure user registration is required when purchasing subscriptions. + add_filter( 'woocommerce_checkout_registration_required', array( __CLASS__, 'require_registration_during_checkout' ) ); + add_action( 'woocommerce_before_checkout_process', array( __CLASS__, 'force_registration_during_checkout' ), 10 ); + add_filter( 'woocommerce_checkout_registration_enabled', array( __CLASS__, 'maybe_enable_registration' ) ); + + // Override the WC default "Add to cart" text to "Sign up now" (in various places/templates) + add_filter( 'woocommerce_order_button_text', array( __CLASS__, 'order_button_text' ) ); } /** @@ -50,7 +56,7 @@ class WC_Subscriptions_Checkout { */ public static function attach_dependant_hooks() { // Make sure guest checkout is not enabled in option param passed to WC JS - if ( WC_Subscriptions::is_woocommerce_pre( '3.3' ) ) { + if ( wcs_is_woocommerce_pre( '3.3' ) ) { add_filter( 'woocommerce_params', array( __CLASS__, 'filter_woocommerce_script_parameters' ), 10, 1 ); add_filter( 'wc_checkout_params', array( __CLASS__, 'filter_woocommerce_script_parameters' ), 10, 1 ); } else { @@ -65,13 +71,13 @@ class WC_Subscriptions_Checkout { * @param array $posted_data The data posted on checkout * @since 2.0 */ - public static function process_checkout( $order_id, $posted_data ) { + public static function process_checkout( $order_id, $posted_data = array() ) { if ( ! WC_Subscriptions_Cart::cart_contains_subscription() ) { return; } - $order = new WC_Order( $order_id ); + $order = wc_get_order( $order_id ); $subscriptions = array(); @@ -114,37 +120,46 @@ class WC_Subscriptions_Checkout { * @since 2.0 */ public static function create_subscription( $order, $cart, $posted_data ) { - global $wpdb; try { // Start transaction if available - $wpdb->query( 'START TRANSACTION' ); + $transaction = new WCS_SQL_Transaction(); + $transaction->start(); // Set the recurring line totals on the subscription $variation_id = wcs_cart_pluck( $cart, 'variation_id' ); $product_id = empty( $variation_id ) ? wcs_cart_pluck( $cart, 'product_id' ) : $variation_id; - $subscription = wcs_create_subscription( array( - 'start_date' => $cart->start_date, - 'order_id' => wcs_get_objects_property( $order, 'id' ), - 'customer_id' => $order->get_user_id(), - 'billing_period' => wcs_cart_pluck( $cart, 'subscription_period' ), - 'billing_interval' => wcs_cart_pluck( $cart, 'subscription_period_interval' ), - 'customer_note' => wcs_get_objects_property( $order, 'customer_note' ), - ) ); + $subscription = wcs_create_subscription( + array( + 'start_date' => $cart->start_date, + 'order_id' => wcs_get_objects_property( $order, 'id' ), + 'customer_id' => $order->get_user_id(), + 'billing_period' => wcs_cart_pluck( $cart, 'subscription_period' ), + 'billing_interval' => wcs_cart_pluck( $cart, 'subscription_period_interval' ), + 'customer_note' => wcs_get_objects_property( $order, 'customer_note' ), + ) + ); if ( is_wp_error( $subscription ) ) { + // If the customer wasn't created on checkout and registration isn't enabled, display a more appropriate error message. + if ( 'woocommerce_subscription_invalid_customer_id' === $subscription->get_error_code() && ! is_user_logged_in() && ! WC()->checkout->is_registration_enabled() ) { + throw new Exception( self::get_registration_error_message() ); + } + throw new Exception( $subscription->get_error_message() ); } // Set the subscription's billing and shipping address $subscription = wcs_copy_order_address( $order, $subscription ); - $subscription->update_dates( array( - 'trial_end' => $cart->trial_end_date, - 'next_payment' => $cart->next_payment_date, - 'end' => $cart->end_date, - ) ); + $subscription->update_dates( + array( + 'trial_end' => $cart->trial_end_date, + 'next_payment' => $cart->next_payment_date, + 'end' => $cart->end_date, + ) + ); // Store trial period for PayPal if ( wcs_cart_pluck( $cart, 'subscription_trial_length' ) > 0 ) { @@ -159,7 +174,7 @@ class WC_Subscriptions_Checkout { $subscription->set_payment_method( $available_gateways[ $order_payment_method ] ); } - if ( ! $cart->needs_payment() || 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) { + if ( ! $cart->needs_payment() || wcs_is_manual_renewal_required() ) { $subscription->set_requires_manual_renewal( true ); } elseif ( ! isset( $available_gateways[ $order_payment_method ] ) || ! $available_gateways[ $order_payment_method ]->supports( 'subscriptions' ) ) { $subscription->set_requires_manual_renewal( true ); @@ -234,11 +249,11 @@ class WC_Subscriptions_Checkout { $subscription->save(); // If we got here, the subscription was created without problems - $wpdb->query( 'COMMIT' ); + $transaction->commit(); } catch ( Exception $e ) { // There was an error adding the subscription - $wpdb->query( 'ROLLBACK' ); + $transaction->rollback(); return new WP_Error( 'checkout-error', $e->getMessage() ); } @@ -256,44 +271,41 @@ class WC_Subscriptions_Checkout { // We need to make sure we only get recurring shipping packages WC_Subscriptions_Cart::set_calculation_type( 'recurring_total' ); + WC_Subscriptions_Cart::set_recurring_cart_key( $cart->recurring_cart_key ); - foreach ( $cart->get_shipping_packages() as $package_index => $base_package ) { + if ( $cart->needs_shipping() ) { + foreach ( $cart->get_shipping_packages() as $recurring_cart_package_key => $recurring_cart_package ) { + $package_index = isset( $recurring_cart_package['package_index'] ) ? $recurring_cart_package['package_index'] : 0; + $package = WC_Subscriptions_Cart::get_calculated_shipping_for_package( $recurring_cart_package ); + $shipping_method_id = isset( WC()->checkout()->shipping_methods[ $package_index ] ) ? WC()->checkout()->shipping_methods[ $package_index ] : ''; - $package = WC_Subscriptions_Cart::get_calculated_shipping_for_package( $base_package ); - - $recurring_shipping_package_key = WC_Subscriptions_Cart::get_recurring_shipping_package_key( $cart->recurring_cart_key, $package_index ); - - $shipping_method_id = isset( WC()->checkout()->shipping_methods[ $package_index ] ) ? WC()->checkout()->shipping_methods[ $package_index ] : ''; - - if ( isset( WC()->checkout()->shipping_methods[ $recurring_shipping_package_key ] ) ) { - $shipping_method_id = WC()->checkout()->shipping_methods[ $recurring_shipping_package_key ]; - $package_key = $recurring_shipping_package_key; - } else { - $package_key = $package_index; - } - - if ( isset( $package['rates'][ $shipping_method_id ] ) ) { - - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - - $item_id = $subscription->add_shipping( $package['rates'][ $shipping_method_id ] ); - - // Allows plugins to add order item meta to shipping - do_action( 'woocommerce_add_shipping_order_item', $subscription->get_id(), $item_id, $package_key ); - do_action( 'woocommerce_subscriptions_add_recurring_shipping_order_item', $subscription->get_id(), $item_id, $package_key ); - - } else { // WC 3.0+ + if ( isset( WC()->checkout()->shipping_methods[ $recurring_cart_package_key ] ) ) { + $shipping_method_id = WC()->checkout()->shipping_methods[ $recurring_cart_package_key ]; + $package_key = $recurring_cart_package_key; + } else { + $package_key = $package_index; + } + if ( isset( $package['rates'][ $shipping_method_id ] ) ) { $shipping_rate = $package['rates'][ $shipping_method_id ]; $item = new WC_Order_Item_Shipping(); $item->legacy_package_key = $package_key; // @deprecated For legacy actions. - $item->set_props( array( - 'method_title' => $shipping_rate->label, - 'method_id' => $shipping_rate->id, - 'total' => wc_format_decimal( $shipping_rate->cost ), - 'taxes' => array( 'total' => $shipping_rate->taxes ), - 'order_id' => $subscription->get_id(), - ) ); + $item->set_props( + array( + 'method_title' => $shipping_rate->label, + 'total' => wc_format_decimal( $shipping_rate->cost ), + 'taxes' => array( 'total' => $shipping_rate->taxes ), + 'order_id' => $subscription->get_id(), + ) + ); + + // Backwards compatibility for sites running WC pre 3.4 which stored shipping method and instance ID in a single meta row. + if ( wcs_is_woocommerce_pre( '3.4' ) ) { + $item->set_method_id( $shipping_rate->id ); + } else { + $item->set_method_id( $shipping_rate->method_id ); + $item->set_instance_id( $shipping_rate->instance_id ); + } foreach ( $shipping_rate->get_meta_data() as $key => $value ) { $item->add_meta_data( $key, $value, true ); @@ -311,6 +323,7 @@ class WC_Subscriptions_Checkout { } WC_Subscriptions_Cart::set_calculation_type( 'none' ); + WC_Subscriptions_Cart::set_recurring_cart_key( 'none' ); } /** @@ -350,9 +363,7 @@ class WC_Subscriptions_Checkout { * @since 2.0 */ public static function add_cart_item( $subscription, $cart_item, $cart_item_key ) { - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - _deprecated_function( __METHOD__, '2.2.0', 'WC_Checkout::create_order_line_items( $subscription, $cart )' ); - } + _deprecated_function( __METHOD__, '2.2.0', 'WC_Checkout::create_order_line_items( $subscription, $cart )' ); $item_id = $subscription->add_product( $cart_item['data'], @@ -381,13 +392,8 @@ class WC_Subscriptions_Checkout { } // Allow plugins to add order item meta - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - do_action( 'woocommerce_add_order_item_meta', $item_id, $cart_item, $cart_item_key ); - do_action( 'woocommerce_add_subscription_item_meta', $item_id, $cart_item, $cart_item_key ); - } else { - wc_do_deprecated_action( 'woocommerce_add_order_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' ); - wc_do_deprecated_action( 'woocommerce_add_subscription_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' ); - } + wc_do_deprecated_action( 'woocommerce_add_order_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' ); + wc_do_deprecated_action( 'woocommerce_add_subscription_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' ); return $item_id; } @@ -410,65 +416,6 @@ class WC_Subscriptions_Checkout { _deprecated_function( __METHOD__, '2.0' ); } - /** - * If shopping cart contains subscriptions, make sure a user can register on the checkout page - * - * @since 1.0 - */ - public static function make_checkout_registration_possible( $checkout = '' ) { - - if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() ) { - - // Make sure users are required to register an account - if ( true === $checkout->enable_guest_checkout ) { - $checkout->enable_guest_checkout = false; - self::$guest_checkout_option_changed = true; - - $checkout->must_create_account = true; - } - } - } - - /** - * Make sure account fields display the required "*" when they are required. - * - * @since 1.3.5 - */ - public static function make_checkout_account_fields_required( $checkout_fields ) { - - if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() ) { - - $account_fields = array( - 'account_username', - 'account_password', - 'account_password-2', - ); - - foreach ( $account_fields as $account_field ) { - if ( isset( $checkout_fields['account'][ $account_field ] ) ) { - $checkout_fields['account'][ $account_field ]['required'] = true; - } - } - } - - return $checkout_fields; - } - - /** - * After displaying the checkout form, restore the store's original registration settings. - * - * @since 1.1 - */ - public static function restore_checkout_registration_settings( $checkout = '' ) { - - if ( self::$guest_checkout_option_changed ) { - $checkout->enable_guest_checkout = true; - if ( ! is_user_logged_in() ) { // Also changed must_create_account - $checkout->must_create_account = false; - } - } - } - /** * Also make sure the guest checkout option value passed to the woocommerce.js forces registration. * Otherwise the registration form is hidden by woocommerce.js. @@ -492,6 +439,22 @@ class WC_Subscriptions_Checkout { return $woocommerce_params; } + /** + * Stores the subtracted base location tax totals in the subscription line item meta. + * + * @since 3.0.10 + * + * @param WC_Line_Item_Product $line_item The line item added to the order/subscription. + * @param string $cart_item_key The key of the cart item being added to the cart. + * @param array $cart_item The cart item data. + */ + public static function store_line_item_base_location_taxes( $line_item, $cart_item_key, $cart_item ) { + if ( isset( $cart_item['_subtracted_base_location_taxes'] ) ) { + $line_item->add_meta_data( '_subtracted_base_location_taxes', $cart_item['_subtracted_base_location_taxes'] ); + $line_item->add_meta_data( '_subtracted_base_location_rates', $cart_item['_subtracted_base_location_rates'] ); + } + } + /** * Also make sure the guest checkout option value passed to the woocommerce.js forces registration. * Otherwise the registration form is hidden by woocommerce.js. @@ -505,17 +468,81 @@ class WC_Subscriptions_Checkout { return self::filter_woocommerce_script_parameters( $woocommerce_params, $handle ); } + /** + * Enables the 'registeration required' (guest checkout) setting when purchasing subscriptions. + * + * @since 3.1.0 + * + * @param bool $account_required Whether an account is required to checkout. + * @return bool + */ + public static function require_registration_during_checkout( $account_required ) { + if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() ) { + $account_required = true; + } + + return $account_required; + } + /** * During the checkout process, force registration when the cart contains a subscription. * * @since 1.1 + * @param $woocommerce_params This parameter is not used. */ public static function force_registration_during_checkout( $woocommerce_params ) { - if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() ) { $_POST['createaccount'] = 1; } + } + /** + * Generates a registration failed error message depending on the store's registration settings. + * + * When a customer wasn't created on checkout because checkout registration is disabled, + * this function generates the error message displayed to the customer. + * + * The message will redirect the customer to the My Account page if registration is enabled there, otherwise a generic 'you need an account' message will be displayed. + * + * @since 3.0.11 + * @return string The error message. + */ + private static function get_registration_error_message() { + // Direct the customer to login/register on the my account page if that's enabled. + if ( 'yes' === get_option( 'woocommerce_enable_myaccount_registration' ) ) { + // Translators: Placeholders are opening and closing strong and link tags. + $message = __( 'Purchasing a subscription product requires an account. Please go to the %1$sMy Account%2$s page to login or register.', 'woocommerce-subscriptions' ); + } else { + // Translators: Placeholders are opening and closing strong and link tags. + $message = __( 'Purchasing a subscription product requires an account. Please go to the %1$sMy Account%2$s page to login or contact us if you need assistance.', 'woocommerce-subscriptions' ); + } + + return sprintf( $message, '', '' ); + } + + /** + * Enables registration for carts containing subscriptions if admin allow it. + * + * @since 3.1.0 + * + * @param bool $registration_enabled Whether registration is enabled on checkout by default. + * @return bool + */ + public static function maybe_enable_registration( $registration_enabled ) { + // Exit early if regristration is already allowed. + if ( $registration_enabled ) { + return $registration_enabled; + } + + if ( is_user_logged_in() || ! WC_Subscriptions_Cart::cart_contains_subscription() ) { + return $registration_enabled; + } + + if ( apply_filters( 'wc_is_registration_enabled_for_subscription_purchases', 'yes' === get_option( 'woocommerce_enable_signup_from_checkout_for_subscriptions', 'yes' ) ) ) { + $registration_enabled = true; + } + + return $registration_enabled; } /** @@ -539,4 +566,87 @@ class WC_Subscriptions_Checkout { _deprecated_function( __METHOD__, '2.0', 'WCS_Cart_Renewal::filter_my_account_my_orders_actions()' ); return $actions; } + + /** + * If shopping cart contains subscriptions, make sure a user can register on the checkout page + * + * @since 1.0 + * @deprecated 3.1.0 + */ + public static function make_checkout_registration_possible( $checkout = '' ) { + wcs_deprecated_function( __METHOD__, '3.1.0' ); + if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() ) { + + // Make sure users are required to register an account + if ( true === $checkout->enable_guest_checkout ) { + $checkout->enable_guest_checkout = false; + self::$guest_checkout_option_changed = true; + + $checkout->must_create_account = true; + } + } + } + + /** + * Make sure account fields display the required "*" when they are required. + * + * @since 1.3.5 + * @deprecated 3.1.0 + */ + public static function make_checkout_account_fields_required( $checkout_fields ) { + wcs_deprecated_function( __METHOD__, '3.1.0' ); + if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() ) { + + $account_fields = array( + 'account_username', + 'account_password', + 'account_password-2', + ); + + foreach ( $account_fields as $account_field ) { + if ( isset( $checkout_fields['account'][ $account_field ] ) ) { + $checkout_fields['account'][ $account_field ]['required'] = true; + } + } + } + + return $checkout_fields; + } + + /** + * After displaying the checkout form, restore the store's original registration settings. + * + * @since 1.1 + * @deprecated 3.1.0 + */ + public static function restore_checkout_registration_settings( $checkout = '' ) { + wcs_deprecated_function( __METHOD__, '3.1.0' ); + if ( self::$guest_checkout_option_changed ) { + $checkout->enable_guest_checkout = true; + if ( ! is_user_logged_in() ) { // Also changed must_create_account + $checkout->must_create_account = false; + } + } + } + + /** + * Overrides the "Place order" button text with "Sign up now" when the cart contains initial subscription purchases. + * + * @since 4.0.0 + * + * @param string $button_text The place order button text. + * @return string $button_text + */ + public static function order_button_text( $button_text ) { + if ( ! WC_Subscriptions_Cart::cart_contains_subscription() ) { + return $button_text; + } + + // Return the default button text if the cart contains a Subscription order type. The button text for these carts is filtered separately. + if ( wcs_cart_contains_renewal() || wcs_cart_contains_resubscribe() || wcs_cart_contains_switches() ) { + return $button_text; + } + + return apply_filters( 'wcs_place_subscription_order_text', __( 'Sign up now', 'woocommerce-subscriptions' ) ); + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php new file mode 100644 index 0000000..9c27d10 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php @@ -0,0 +1,587 @@ +autoloader = $autoloader; + } else { + $this->autoloader = new WCS_Core_Autoloader( $this->get_subscriptions_core_directory() ); + $this->autoloader->register(); + } + + $this->define_constants(); + $this->includes(); + $this->init(); + $this->init_hooks(); + + // Store this instance so we can access it globally. + self::$instance = $this; + } + + /** + * Gets the Subscriptions Core instance. + * + * @since 4.0.0 + * @return WC_Subscriptions_Core_Plugin + */ + public static function instance() { + if ( ! self::$instance ) { + // Doing it wrong. WC_Subscriptions_Core_Plugin::instance() should not be called before an instance has been created. + } + + return self::$instance; + } + + /** + * Defines WC Subscriptions contants. + */ + protected function define_constants() { + define( 'WCS_INIT_TIMESTAMP', gmdate( 'U' ) ); + } + + /** + * Includes required files. + */ + protected function includes() { + // Load function files. + require_once $this->get_subscriptions_core_directory( 'wcs-functions.php' ); + require_once $this->get_subscriptions_core_directory( 'includes/gateways/paypal/includes/wcs-paypal-functions.php' ); + } + + /** + * Initialise the plugin. + */ + public function init() { + $payment_gateways_handler = $this->get_gateways_handler_class(); + + WC_Subscriptions_Coupon::init(); + WC_Subscriptions_Product::init(); + WC_Subscriptions_Admin::init(); + WC_Subscriptions_Manager::init(); + WC_Subscriptions_Cart::init(); + WC_Subscriptions_Cart_Validator::init(); + WC_Subscriptions_Order::init(); + WC_Subscriptions_Renewal_Order::init(); + WC_Subscriptions_Checkout::init(); + WC_Subscriptions_Email::init(); + WC_Subscriptions_Addresses::init(); + WC_Subscriptions_Change_Payment_Gateway::init(); + $payment_gateways_handler::init(); + WCS_PayPal_Standard_Change_Payment_Method::init(); + WC_Subscriptions_Tracker::init(); + WCS_Upgrade_Logger::init(); + new WCS_Cart_Renewal(); + new WCS_Cart_Resubscribe(); + new WCS_Cart_Initial_Payment(); + WCS_Download_Handler::init(); + WCS_Limiter::init(); + WCS_Admin_System_Status::init(); + WCS_Staging::init(); + WCS_Permalink_Manager::init(); + WCS_Custom_Order_Item_Manager::init(); + WCS_Dependent_Hook_Manager::init(); + WCS_Admin_Product_Import_Export_Manager::init(); + WC_Subscriptions_Frontend_Scripts::init(); + + add_action( 'init', array( 'WC_Subscriptions_Synchroniser', 'init' ) ); + add_action( 'after_setup_theme', array( 'WC_Subscriptions_Upgrader', 'init' ), 11 ); + add_action( 'init', array( 'WC_PayPal_Standard_Subscriptions', 'init' ), 11 ); + add_action( 'init', array( 'WCS_WC_Admin_Manager', 'init' ), 11 ); + + // Attach the callback to load version dependant classes. + add_action( 'plugins_loaded', array( $this, 'init_version_dependant_classes' ) ); + + // Initialised the related order and customter data store instances. + add_action( 'plugins_loaded', 'WCS_Related_Order_Store::instance' ); + add_action( 'plugins_loaded', 'WCS_Customer_Store::instance' ); + + // Initialise the scheduler. + $scheduler_class = apply_filters( 'woocommerce_subscriptions_scheduler', 'WCS_Action_Scheduler' ); + $this->scheduler = new $scheduler_class(); + + // Initialise the cache. + $this->cache = WCS_Cache_Manager::get_instance(); + + if ( class_exists( 'Automattic\WooCommerce\Blocks\Package' ) && version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '4.4.0', '>' ) ) { + // When WooCommerceBlocks is loaded, set up the Integration class. + add_action( 'woocommerce_blocks_loaded', array( $this, 'setup_blocks_integration' ) ); + add_action( 'woocommerce_blocks_loaded', array( 'WC_Subscriptions_Extend_Store_Endpoint', 'init' ) ); + } + + if ( ! $payment_gateways_handler::are_zero_total_subscriptions_allowed() ) { + WC_Subscriptions_Gateway_Restrictions_Manager::init(); + } + } + + /** + * Initialises classes which need to be loaded after other plugins have loaded. + * + * Hooked onto 'plugins_loaded' by @see WC_Subscriptions_Plugin::init() + */ + public function init_version_dependant_classes() { + new WCS_Admin_Post_Types(); + new WCS_Admin_Meta_Boxes(); + WCS_Template_Loader::init(); + WCS_Remove_Item::init(); + WCS_User_Change_Status_Handler::init(); + WCS_My_Account_Payment_Methods::init(); + WCS_My_Account_Auto_Renew_Toggle::init(); + new WCS_Deprecated_Filter_Hooks(); + + // On some loads the WC_Query doesn't exist. To avoid a fatal, only load the WCS_Query class when it exists. + if ( class_exists( 'WC_Query' ) ) { + new WCS_Query(); + } + + $failed_scheduled_action_manager = new WCS_Failed_Scheduled_Action_Manager( new WC_Logger() ); + $failed_scheduled_action_manager->init(); + + /** + * Allow third-party code to enable running v2.0 hook deprecation handling for stores that might want to check for deprecated code. + * + * @param bool Whether the hook deprecation handlers should be loaded. False by default. + */ + if ( apply_filters( 'woocommerce_subscriptions_load_deprecation_handlers', false ) ) { + new WCS_Action_Deprecator(); + new WCS_Filter_Deprecator(); + new WCS_Dynamic_Action_Deprecator(); + new WCS_Dynamic_Filter_Deprecator(); + } + + // Only load privacy handling on WC applicable versions. + if ( class_exists( 'WC_Abstract_Privacy' ) ) { + new WCS_Privacy(); + } + } + + /** + * Attaches the hooks to init/setup the plugin. + * + * @since 4.0.0 + */ + public function init_hooks() { + register_deactivation_hook( $this->get_plugin_file(), array( $this, 'deactivate_plugin' ) ); + + // Register our custom subscription order type after WC_Post_types::register_post_types() + add_action( 'init', array( $this, 'register_order_types' ), 6 ); + + add_filter( 'woocommerce_data_stores', array( $this, 'add_data_stores' ) ); + + // Register our custom subscription order statuses before WC_Post_types::register_post_status() + add_action( 'init', array( $this, 'register_post_statuses' ), 9 ); + + // Load translation files + add_action( 'init', array( $this, 'load_plugin_textdomain' ), 3 ); + + // Add the "Settings | Documentation" links on the Plugins administration screen + add_filter( 'plugin_action_links_' . plugin_basename( $this->get_plugin_file() ), array( $this, 'add_plugin_action_links' ) ); + add_action( 'in_plugin_update_message-' . plugin_basename( $this->get_plugin_file() ), array( $this, 'update_notice' ), 10, 2 ); + + add_action( 'init', array( $this, 'activate_plugin' ) ); + + add_filter( 'action_scheduler_queue_runner_batch_size', array( $this, 'reduce_multisite_action_scheduler_batch_size' ) ); + } + + /** + * Gets the subscriptions core directory. + * + * @since 4.0.0 + * @param string $path Optional. The path to append. + * @return string + */ + public function get_subscriptions_core_directory( $path = '' ) { + return $path ? trailingslashit( dirname( __DIR__ ) ) . $path : dirname( __DIR__ ); + } + + /** + * Gets the subscriptions core directory url. + * + * @since 4.0.0 + * @param string $path Optional. The path to append. + * @return string + */ + public function get_subscriptions_core_directory_url( $path = '' ) { + return plugin_dir_url( __DIR__ ) . $path; + } + + /** + * Gets the plugin's version + * + * @since 4.0.0 + */ + public function get_plugin_version() { + return $this->plugin_version; + } + + /** + * Gets the plugin file name + * + * @return string The plugin file + */ + public function get_plugin_file() { + return __FILE__; + } + + /** + * Gets the autoloader instance. + * + * @return WCS_Autoloader + */ + public function get_autoloader() { + return $this->autoloader; + } + + /** + * Gets the product type name. + * + * @return string The product type name. + */ + public function get_product_type_name() { + return 'subscription'; + } + + /** + * Gets the activation transient name. + * + * @return string The transient name used to record when the plugin was activated. + */ + public function get_activation_transient() { + return 'woocommerce_subscriptions_activated'; + } + + /** + * Gets the core Payment Gateways handler class + * + * @since 4.0.0 + * @return string + */ + public function get_gateways_handler_class() { + return 'WC_Subscriptions_Core_Payment_Gateways'; + } + + /** + * Registers Subscriptions order types. + * + * @since 4.0.0 + */ + public function register_order_types() { + $subscriptions_exist = $this->cache->cache_and_get( 'wcs_do_subscriptions_exist', 'wcs_do_subscriptions_exist' ); + + if ( true === (bool) apply_filters( 'woocommerce_subscriptions_not_empty', $subscriptions_exist ) ) { + $not_found_text = __( 'No Subscriptions found', 'woocommerce-subscriptions' ); + } else { + $not_found_text = '

    ' . __( 'Subscriptions will appear here for you to view and manage once purchased by a customer.', 'woocommerce-subscriptions' ) . '

    '; + // translators: placeholders are opening and closing link tags + $not_found_text .= '

    ' . sprintf( __( '%1$sLearn more about managing subscriptions »%2$s', 'woocommerce-subscriptions' ), '', '' ) . '

    '; + // translators: placeholders are opening and closing link tags + $not_found_text .= '

    ' . sprintf( __( '%1$sAdd a subscription product »%2$s', 'woocommerce-subscriptions' ), '', '' ) . '

    '; + } + + $subscriptions_not_found_text = apply_filters( 'woocommerce_subscriptions_not_found_label', $not_found_text ); + + wc_register_order_type( + 'shop_subscription', + apply_filters( + 'woocommerce_register_post_type_subscription', + array( + // register_post_type() params + 'labels' => array( + 'name' => __( 'Subscriptions', 'woocommerce-subscriptions' ), + 'singular_name' => __( 'Subscription', 'woocommerce-subscriptions' ), + 'add_new' => _x( 'Add Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), + 'add_new_item' => _x( 'Add New Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), + 'edit' => _x( 'Edit', 'custom post type setting', 'woocommerce-subscriptions' ), + 'edit_item' => _x( 'Edit Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), + 'new_item' => _x( 'New Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), + 'view' => _x( 'View Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), + 'view_item' => _x( 'View Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), + 'search_items' => __( 'Search Subscriptions', 'woocommerce-subscriptions' ), + 'not_found' => $subscriptions_not_found_text, + 'not_found_in_trash' => _x( 'No Subscriptions found in trash', 'custom post type setting', 'woocommerce-subscriptions' ), + 'parent' => _x( 'Parent Subscriptions', 'custom post type setting', 'woocommerce-subscriptions' ), + 'menu_name' => __( 'Subscriptions', 'woocommerce-subscriptions' ), + ), + 'description' => __( 'This is where subscriptions are stored.', 'woocommerce-subscriptions' ), + 'public' => false, + 'show_ui' => true, + 'capability_type' => 'shop_order', + 'map_meta_cap' => true, + 'publicly_queryable' => false, + 'exclude_from_search' => true, + 'show_in_menu' => current_user_can( 'manage_woocommerce' ) ? 'woocommerce' : true, + 'hierarchical' => false, + 'show_in_nav_menus' => false, + 'rewrite' => false, + 'query_var' => false, + 'supports' => array( 'title', 'comments', 'custom-fields' ), + 'has_archive' => false, + + // wc_register_order_type() params + 'exclude_from_orders_screen' => true, + 'add_order_meta_boxes' => true, + 'exclude_from_order_count' => true, + 'exclude_from_order_views' => true, + 'exclude_from_order_webhooks' => true, + 'exclude_from_order_reports' => true, + 'exclude_from_order_sales_reports' => true, + 'class_name' => 'WC_Subscription', + ) + ) + ); + } + + /** + * Registers data stores. + * + * @since 4.0.0 + * @return string[] + */ + public function add_data_stores( $data_stores ) { + // Our custom data stores. + $data_stores['subscription'] = 'WCS_Subscription_Data_Store_CPT'; + $data_stores['product-variable-subscription'] = 'WCS_Product_Variable_Data_Store_CPT'; + + // Use WC core data stores for our products. + $data_stores['product-subscription_variation'] = 'WC_Product_Variation_Data_Store_CPT'; + $data_stores['order-item-line_item_pending_switch'] = 'WC_Order_Item_Product_Data_Store'; + + return $data_stores; + } + + /** + * Registers our custom post statuses, used for subscription statuses. + * + * @since 4.0.0 + */ + public function register_post_statuses() { + $subscription_statuses = wcs_get_subscription_statuses(); + $registered_statuses = apply_filters( + 'woocommerce_subscriptions_registered_statuses', + array( + // translators: placeholder is a post count. + 'wc-active' => _nx_noop( 'Active (%s)', 'Active (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), + // translators: placeholder is a post count. + 'wc-switched' => _nx_noop( 'Switched (%s)', 'Switched (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), + // translators: placeholder is a post count. + 'wc-expired' => _nx_noop( 'Expired (%s)', 'Expired (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), + // translators: placeholder is a post count. + 'wc-pending-cancel' => _nx_noop( 'Pending Cancellation (%s)', 'Pending Cancellation (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), + ) + ); + + if ( is_array( $subscription_statuses ) && is_array( $registered_statuses ) ) { + foreach ( $registered_statuses as $status => $label_count ) { + register_post_status( + $status, + array( + 'label' => $subscription_statuses[ $status ], // use same label/translations as wcs_get_subscription_statuses() + 'public' => false, + 'exclude_from_search' => false, + 'show_in_admin_all_list' => true, + 'show_in_admin_status_list' => true, + 'label_count' => $label_count, + ) + ); + } + } + } + + /** + * Runs the required processes when the plugin is deactivated. + * + * @since 4.0.0 + */ + public function deactivate_plugin() { + delete_option( WC_Subscriptions_Admin::$option_prefix . '_is_active' ); + flush_rewrite_rules(); + do_action( 'woocommerce_subscriptions_deactivated' ); + } + + /** + * Runs the required process on plugin activation. + * + * @since 4.0.0 + */ + public function activate_plugin() { + $is_active = get_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', false ); + + if ( false === $is_active ) { + + // Add the "Subscriptions" product type + if ( ! get_term_by( 'slug', $this->get_product_type_name(), 'product_type' ) ) { + wp_insert_term( $this->get_product_type_name(), 'product_type' ); + } + + // Maybe add the "Variable Subscriptions" product type + if ( ! get_term_by( 'slug', 'variable-subscription', 'product_type' ) ) { + wp_insert_term( __( 'Variable Subscription', 'woocommerce-subscriptions' ), 'product_type' ); + } + + // If no Subscription settings exist, its the first activation, so add defaults + if ( ! WC_Subscriptions_Admin::has_settings() ) { + WC_Subscriptions_Admin::add_default_settings(); + } + + // if this is the first time activating WooCommerce Subscription we want to enable PayPal debugging by default. + if ( '0' == get_option( WC_Subscriptions_Admin::$option_prefix . '_previous_version', '0' ) && false == get_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', false ) ) { + $paypal_settings = get_option( 'woocommerce_paypal_settings' ); + $paypal_settings['debug'] = 'yes'; + update_option( 'woocommerce_paypal_settings', $paypal_settings ); + update_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', 'true' ); + } + + update_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', true ); + + set_transient( $this->get_activation_transient(), true, 60 * 60 ); + + flush_rewrite_rules(); + + do_action( 'woocommerce_subscriptions_activated' ); + } + } + + /** + * Registers plugin translation files. + * + * @since 4.0.0 + */ + public function load_plugin_textdomain() { + $plugin_rel_path = apply_filters( 'woocommerce_subscriptions_translation_file_rel_path', $this->get_subscriptions_core_directory() . '/languages' ); + + // Then check for a language file in /wp-content/plugins/woocommerce-subscriptions/languages/ (this will be overriden by any file already loaded) + load_plugin_textdomain( 'woocommerce-subscriptions', false, $plugin_rel_path ); + } + + /** + * Adds the settings, docs and support links to the plugin screen. + * + * @since 4.0.0 + * + * @param string[] $links The plugin's links displayed on the plugin screen. + * @return string[] + */ + public function add_plugin_action_links( $links ) { + $plugin_links = array( + '' . __( 'Settings', 'woocommerce-subscriptions' ) . '', + '' . _x( 'Docs', 'short for documents', 'woocommerce-subscriptions' ) . '', + '' . __( 'Support', 'woocommerce-subscriptions' ) . '', + ); + + return array_merge( $plugin_links, $links ); + } + + /** + * Displays an upgrade notice for stores upgrading to 2.0.0. + * + * @since 4.0.0 + * + * @param array $plugin_data Information about the plugin. + * @param array $r response from the server about the new version. + */ + public function update_notice( $plugin_data, $r ) { + + // Bail if the update notice is not relevant (new version is not yet 2.0 or we're already on 2.0) + if ( version_compare( '2.0.0', $plugin_data['new_version'], '>' ) || version_compare( '2.0.0', $plugin_data['Version'], '<=' ) ) { + return; + } + + $update_notice = '
    '; + // translators: placeholders are opening and closing tags. Leads to docs on version 2 + $update_notice .= sprintf( __( 'Warning! Version 2.0 is a major update to the WooCommerce Subscriptions extension. Before updating, please create a backup, update all WooCommerce extensions and test all plugins, custom code and payment gateways with version 2.0 on a staging site. %1$sLearn more about the changes in version 2.0 »%2$s', 'woocommerce-subscriptions' ), '', '' ); + $update_notice .= '
    '; + + echo wp_kses_post( $update_notice ); + } + + /** + * Sets up the Blocks integration class. + * + * @since 4.0.0 + */ + public function setup_blocks_integration() { + /** + * Filter the compatible blocks for WooCommerce Subscriptions. + */ + $compatible_blocks = apply_filters( + 'wcs_compatible_blocks', + [ 'cart', 'checkout', 'mini-cart' ] + ); + + foreach ( $compatible_blocks as $block_name ) { + add_action( + "woocommerce_blocks_{$block_name}_block_registration", + function( $integration_registry ) { + $integration_registry->register( new WCS_Blocks_Integration() ); + } + ); + } + } + + /** + * Reduces the default Action Scheduler batch size on multi-sites. + * + * Renewals use a lot more memory on WordPress multisite (10-15mb instead of 0.1-1mb) so + * we need to reduce the number of renewals run in each request. + * + * @since 4.0.0 + * + * @param int $batch_size The default Action Scheduler batch size. + * @return int + */ + public function reduce_multisite_action_scheduler_batch_size( $batch_size ) { + if ( is_multisite() ) { + $batch_size = 10; + } + + return $batch_size; + } +} diff --git a/includes/class-wc-subscriptions-coupon.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php similarity index 81% rename from includes/class-wc-subscriptions-coupon.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php index cd44625..58c1e2f 100644 --- a/includes/class-wc-subscriptions-coupon.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-coupon.php @@ -92,40 +92,10 @@ class WC_Subscriptions_Coupon { add_filter( 'woocommerce_cart_totals_coupon_html', __CLASS__ . '::mark_recurring_coupon_in_initial_cart_for_hiding', 10, 3 ); - // Hook recurring coupon functionality. - add_action( 'plugins_loaded', array( __CLASS__, 'maybe_add_recurring_coupon_hooks' ) ); - add_filter( 'woocommerce_coupon_is_valid_for_product', array( __CLASS__, 'validate_subscription_coupon_for_product' ), 10, 3 ); add_filter( 'woocommerce_coupon_get_apply_quantity', array( __CLASS__, 'override_applied_quantity_for_recurring_carts' ), 10, 3 ); } - /** - * Maybe add Recurring Coupon functionality. - * - * WC 3.2 added many API enhancements, especially around coupons. It would be very challenging to implement - * this functionality in older versions of WC, so we require 3.2+ to enable this. - * - * @author Jeremy Pry - */ - public static function maybe_add_recurring_coupon_hooks() { - if ( WC_Subscriptions::is_woocommerce_pre( '3.2' ) ) { - return; - } - - // Add custom coupon fields. - add_action( 'woocommerce_coupon_options', array( __CLASS__, 'add_coupon_fields' ), 10 ); - add_action( 'woocommerce_coupon_options_save', array( __CLASS__, 'save_coupon_fields' ), 10 ); - - // Filter the available payment gateways. - add_filter( 'woocommerce_available_payment_gateways', array( __CLASS__, 'gateways_subscription_amount_changes' ), 20 ); - - // Check coupons when a subscription is renewed. - add_action( 'woocommerce_subscription_payment_complete', array( __CLASS__, 'check_coupon_usages' ) ); - - // Add info to the Coupons list table. - add_action( 'manage_shop_coupon_posts_custom_column', array( __CLASS__, 'add_limit_to_list_table' ), 20, 2 ); - } - /** * When all items in the cart have free trial, a recurring coupon should not be applied to the main cart. * Mark such recurring coupons with a dummy span with class wcs-hidden-coupon so that it can be hidden. @@ -260,11 +230,30 @@ class WC_Subscriptions_Coupon { $apply_initial_percent_coupon = true; } + // Get the sign up fee amount depending on the store's tax inclusivity. + if ( wc_prices_include_tax() ) { + $signup_fee = wc_get_price_including_tax( + $cart_item['data'], + array( + 'qty' => 1, + 'price' => WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] ), + ) + ); + } else { + $signup_fee = wc_get_price_excluding_tax( + $cart_item['data'], + array( + 'qty' => 1, + 'price' => WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] ), + ) + ); + } + // Only Sign up fee coupons apply to sign up fees, adjust the discounting_amount accordingly if ( in_array( $coupon_type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) ) { - $discounting_amount = WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] ); + $discounting_amount = $signup_fee; } else { - $discounting_amount -= WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] ); + $discounting_amount -= $signup_fee; } } @@ -551,7 +540,7 @@ class WC_Subscriptions_Coupon { if ( 'none' === $calculation_type || ! WC_Subscriptions_Cart::cart_contains_subscription() || - ( ! is_checkout() && ! is_cart() && ! defined( 'WOOCOMMERCE_CHECKOUT' ) && ! defined( 'WOOCOMMERCE_CART' ) ) + empty( $cart->recurring_cart_key ) ) { return; } @@ -574,7 +563,7 @@ class WC_Subscriptions_Coupon { * @param string $coupon_type The coupon's discount_type property. * @param string $calculation_type The current calculation type. */ - if ( apply_filters( 'wcs_bypass_coupon_removal', false, $coupon, $coupon_type, $calculation_type ) ) { + if ( apply_filters( 'wcs_bypass_coupon_removal', false, $coupon, $coupon_type, $calculation_type, $cart ) ) { continue; } @@ -583,16 +572,7 @@ class WC_Subscriptions_Coupon { continue; } - if ( 'recurring_total' === $calculation_type ) { - // Special handling for a single payment coupon. - if ( 1 === self::get_coupon_limit( $coupon_code ) && 0 < WC()->cart->get_coupon_discount_amount( $coupon_code ) ) { - $cart->remove_coupon( $coupon_code ); - } - - continue; - } - - if ( ! WC_Subscriptions_Cart::all_cart_items_have_free_trial() ) { + if ( 'recurring_total' === $calculation_type || ! WC_Subscriptions_Cart::all_cart_items_have_free_trial() ) { continue; } @@ -721,127 +701,6 @@ class WC_Subscriptions_Coupon { return $label; } - /** - * Determine whether the cart contains a recurring coupon with set number of renewals. - * - * @author Jeremy Pry - * @return bool - */ - public static function cart_contains_limited_recurring_coupon() { - $has_coupon = false; - $applied_coupons = isset( WC()->cart->applied_coupons ) ? WC()->cart->applied_coupons : array(); - foreach ( $applied_coupons as $code ) { - if ( self::coupon_is_limited( $code ) ) { - $has_coupon = true; - break; - } - } - - return $has_coupon; - } - - /** - * Determine if a given order has a limited use coupon. - * - * @author Jeremy Pry - * - * @param WC_Order|WC_Subscription $order - * - * @return bool - */ - public static function order_has_limited_recurring_coupon( $order ) { - $has_coupon = false; - - foreach ( wcs_get_used_coupon_codes( $order ) as $code ) { - if ( self::coupon_is_limited( $code ) ) { - $has_coupon = true; - break; - } - } - - return $has_coupon; - } - - /** - * Determine if a given recurring cart contains a limited use coupon which when applied to a subscription will reach its usage limit within the subscription's length. - * - * @param WC_Cart $recurring_cart The recurring cart object. - * @return bool - */ - public static function recurring_cart_contains_expiring_coupon( $recurring_cart ) { - $limited_recurring_coupons = array(); - - if ( isset( $recurring_cart->applied_coupons ) ) { - $limited_recurring_coupons = array_filter( $recurring_cart->applied_coupons, array( __CLASS__, 'coupon_is_limited' ) ); - } - - // Bail early if there are no limited coupons applied to the recurring cart or if there is no discount provided. - if ( empty( $limited_recurring_coupons ) || ! $recurring_cart->discount_cart ) { - return false; - } - - $has_expiring_coupon = false; - $subscription_length = wcs_cart_pluck( $recurring_cart, 'subscription_length' ); - $subscription_payments = $subscription_length / wcs_cart_pluck( $recurring_cart, 'subscription_period_interval' ); - - // Limited recurring coupons will always expire at some point on subscriptions with no length. - if ( empty( $subscription_length ) ) { - $has_expiring_coupon = true; - } else { - foreach ( $limited_recurring_coupons as $code ) { - if ( WC_Subscriptions_Coupon::get_coupon_limit( $code ) < $subscription_payments ) { - $has_expiring_coupon = true; - break; - } - } - } - - return $has_expiring_coupon; - } - - /** - * Determine if a given coupon is limited to a certain number of renewals. - * - * @author Jeremy Pry - * - * @param string $code The coupon code. - * - * @return bool - */ - public static function coupon_is_limited( $code ) { - return (bool) self::get_coupon_limit( $code ); - } - - /** - * Get the number of renewals for a limited coupon. - * - * @author Jeremy Pry - * - * @param string $code The coupon code. - * - * @return false|int False for non-recurring coupons, or the limit number for recurring coupons. - * A value of 0 is for unlimited usage. - */ - public static function get_coupon_limit( $code ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.2' ) ) { - return false; - } - - // Retrieve the coupon data. - $coupon = new WC_Coupon( $code ); - $coupon_type = $coupon->get_discount_type(); - - // If we have a virtual coupon, attempt to get the original coupon. - if ( isset( self::$renewal_coupons[ $coupon_type ] ) ) { - $coupon = self::map_virtual_coupon( $code ); - $coupon_type = $coupon->get_discount_type(); - } - - $limited = $coupon->get_meta( self::$coupons_renewals ); - - return isset( self::$recurring_coupons[ $coupon_type ] ) ? intval( $limited ) : false; - } - /** * Get a normal coupon from one of our virtual coupons. * @@ -854,7 +713,7 @@ class WC_Subscriptions_Coupon { * * @return WC_Coupon The original coupon. */ - private static function map_virtual_coupon( $code ) { + public static function map_virtual_coupon( $code ) { add_filter( 'woocommerce_get_shop_coupon_data', '__return_false', 100 ); $coupon = new WC_Coupon( $code ); remove_filter( 'woocommerce_get_shop_coupon_data', '__return_false', 100 ); @@ -863,228 +722,27 @@ class WC_Subscriptions_Coupon { } /** - * Limit payment gateways to those that support changing subscription amounts. + * Checks if a coupon is one of our virtual coupons applied to renewal carts. * - * @author Jeremy Pry + * @since 4.0.0 * - * @param WC_Payment_Gateway[] $gateways The current available gateways. - * - * @return WC_Payment_Gateway[], + * @param string $coupon_type The coupon's type. + * @return bool Whether the coupon is a recuring cart virtual coupon. */ - private static function limit_gateways_subscription_amount_changes( $gateways ) { - foreach ( $gateways as $index => $gateway ) { - if ( $gateway->supports( 'subscriptions' ) && ! $gateway->supports( 'subscription_amount_changes' ) ) { - unset( $gateways[ $index ] ); - } - } - - return $gateways; + public static function is_renewal_cart_coupon( $coupon_type ) { + return isset( self::$renewal_coupons[ $coupon_type ] ); } /** - * Filter the available gateways when there is a recurring coupon. + * Checks if a coupon is one of our recurring coupons. * - * @author Jeremy Pry + * @since 4.0.0 * - * @param WC_Payment_Gateway[] $gateways The available payment gateways. - * - * @return array The filtered payment gateways. + * @param string $coupon_type The coupon's type. + * @return bool Whether the coupon is a recuring cart virtual coupon. */ - public static function gateways_subscription_amount_changes( $gateways ) { - // If there are already no gateways or we're on the order-pay screen, bail early. - if ( empty( $gateways ) || is_wc_endpoint_url( 'order-pay' ) ) { - return $gateways; - } - - // See if this is a request to change payment for an existing subscription. - $change_payment = isset( $_GET['change_payment_method'] ) ? wc_clean( $_GET['change_payment_method'] ) : 0; - $has_limited_coupon = false; - if ( $change_payment && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'] ) ) { - $subscription = wcs_get_subscription( $change_payment ); - $has_limited_coupon = self::order_has_limited_recurring_coupon( $subscription ); - } - - // If the cart doesn't have a limited coupon, and a change payment doesn't have a limited coupon, bail early. - if ( ! self::cart_contains_limited_recurring_coupon() && ! $has_limited_coupon ) { - return $gateways; - } - - // If we got this far, we should limit the gateways as needed. - $gateways = self::limit_gateways_subscription_amount_changes( $gateways ); - - // If there are no gateways now, it's because of the coupon. Filter the 'no available payment methods' message. - if ( empty( $gateways ) ) { - add_filter( 'woocommerce_no_available_payment_methods_message', array( __CLASS__, 'no_available_payment_methods_message' ), 20 ); - } - - return $gateways; - } - - /** - * Filter the message for when no payment gateways are available. - * - * @author Jeremy Pry - * - * @param string $message The current message indicating there are no payment methods available.. - * - * @return string The filtered message indicating there are no payment methods available. - */ - public static function no_available_payment_methods_message( $message ) { - return __( 'Sorry, it seems there are no available payment methods which support the recurring coupon you are using. Please contact us if you require assistance or wish to make alternate arrangements.', 'woocommerce-subscriptions' ); - } - - /** - * Add custom fields to the coupon data form. - * - * @see WC_Meta_Box_Coupon_Data::output() - * @author Jeremy Pry - * - * @param int $id The coupon ID. - */ - public static function add_coupon_fields( $id ) { - $coupon = new WC_Coupon( $id ); - woocommerce_wp_text_input( array( - 'id' => 'wcs_number_payments', - 'label' => __( 'Active for x payments', 'woocommerce-subscriptions' ), - 'placeholder' => __( 'Unlimited payments', 'woocommerce-subscriptions' ), - 'description' => __( 'Coupon will be limited to the given number of payments. It will then be automatically removed from the subscription. "Payments" also includes the initial subscription payment.', 'woocommerce-subscriptions' ), - 'desc_tip' => true, - 'data_type' => 'decimal', - 'value' => $coupon->get_meta( self::$coupons_renewals ), - ) ); - } - - /** - * Save our custom coupon fields. - * - * @see WC_Meta_Box_Coupon_Data::save() - * @author Jeremy Pry - * - * @param int $post_id - */ - public static function save_coupon_fields( $post_id ) { - // Check the nonce (again). - if ( empty( $_POST['woocommerce_meta_nonce'] ) || ! wp_verify_nonce( $_POST['woocommerce_meta_nonce'], 'woocommerce_save_data' ) ) { - return; - } - - $coupon = new WC_Coupon( $post_id ); - $coupon->add_meta_data( self::$coupons_renewals, wc_clean( $_POST['wcs_number_payments'] ), true ); - $coupon->save(); - } - - /** - * Determine how many subscriptions the coupon has been applied to. - * - * @author Jeremy Pry - * - * @param WC_Subscription $subscription The current subscription. - */ - public static function check_coupon_usages( $subscription ) { - // If there aren't any coupons, there's nothing to do. - $coupons = wcs_get_used_coupon_codes( $subscription ); - if ( empty( $coupons ) ) { - return; - } - - // Set up the coupons we're looking for, and an initial count. - $limited_coupons = array(); - foreach ( $coupons as $code ) { - if ( self::coupon_is_limited( $code ) ) { - $limited_coupons[ $code ] = 0; - } - } - - // Don't continue if we have no limited use coupons. - if ( empty( $limited_coupons ) ) { - return; - } - - // Get all related orders, and count the number of uses for each coupon. - $related = $subscription->get_related_orders( 'all' ); - - /** @var WC_Order $order */ - foreach ( $related as $id => $order ) { - // Unpaid orders don't count as usages. - if ( $order->needs_payment() ) { - continue; - } - - /* - * If the order has been refunded, treat coupon as unused. We'll consider the order to be - * refunded when there is a non-null refund amount, and the order total equals the refund amount. - * - * The use of == instead of === is deliberate, to account for differences in amount formatting. - */ - $refunded = $order->get_total_refunded(); - $total = $order->get_total(); - if ( $refunded && $total == $refunded ) { - continue; - } - - // If there was nothing discounted, then consider the coupon unused. - if ( ! $order->get_discount_total() ) { - continue; - } - - // Check for limited coupons, and add them to the count if the provide a discount. - $used_coupons = $order->get_items( 'coupon' ); - - /** @var WC_Order_Item_Coupon $used_coupon */ - foreach ( $used_coupons as $used_coupon ) { - if ( isset( $limited_coupons[ $used_coupon->get_code() ] ) && $used_coupon->get_discount() ) { - $limited_coupons[ $used_coupon->get_code() ]++; - } - } - } - - // Check each coupon to see if it needs to be removed. - foreach ( $limited_coupons as $code => $count ) { - if ( self::get_coupon_limit( $code ) <= $count ) { - $subscription->remove_coupon( $code ); - $subscription->add_order_note( sprintf( - /* translators: %1$s is the coupon code, %2$d is the number of payment usages */ - _n( - 'Limited use coupon "%1$s" removed from subscription. It has been used %2$d time.', - 'Limited use coupon "%1$s" removed from subscription. It has been used %2$d times.', - $count, - 'woocommerce-subscriptions' - ), - $code, - number_format_i18n( $count ) - ) ); - } - } - } - - /** - * Add our limited coupon data to the Coupon list table. - * - * @author Jeremy Pry - * - * @param string $column_name The name of the current column in the table. - * @param int $post_id The coupon post ID. - */ - public static function add_limit_to_list_table( $column_name, $post_id ) { - if ( 'usage' !== $column_name ) { - return; - } - - $limit = self::get_coupon_limit( wc_get_coupon_code_by_id( $post_id ) ); - if ( false === $limit ) { - return; - } - - echo '
    '; - if ( $limit ) { - echo esc_html( sprintf( - /* translators: %d refers to the number of payments the coupon can be used for. */ - _n( 'Active for %d payment', 'Active for %d payments', $limit, 'woocommerce-subscriptions' ), - number_format_i18n( $limit ) - ) ); - } else { - esc_html_e( 'Active for unlimited payments', 'woocommerce-subscriptions' ); - } + public static function is_recurring_coupon( $coupon_type ) { + return isset( self::$recurring_coupons[ $coupon_type ] ); } /* Deprecated */ @@ -1379,4 +1037,204 @@ class WC_Subscriptions_Coupon { public static function apply_subscription_discount_after_tax( $coupon, $cart_item, $price ) { _deprecated_function( __METHOD__, '2.0', 'WooCommerce 2.3 removed after tax discounts. Use ' . __CLASS__ . '::apply_subscription_discount( $original_price, $cart_item, $cart )' ); } + + /** + * Maybe add Recurring Coupon functionality. + * + * WC 3.2 added many API enhancements, especially around coupons. It would be very challenging to implement + * this functionality in older versions of WC, so we require 3.2+ to enable this. + * + * @author Jeremy Pry + * @deprecated 4.0.0 + */ + public static function maybe_add_recurring_coupon_hooks() { + _deprecated_function( __METHOD__, '4.0.0' ); + } + + /** + * Add custom fields to the coupon data form. + * + * @see WC_Meta_Box_Coupon_Data::output() + * @author Jeremy Pry + * + * @param int $id The coupon ID. + * @deprecated 4.0.0 + */ + public static function add_coupon_fields( $id ) { + _deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::add_coupon_fields( $id ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + WCS_Limited_Recurring_Coupon_Manager::add_coupon_fields( $id ); + } + } + + /** + * Save our custom coupon fields. + * + * @see WC_Meta_Box_Coupon_Data::save() + * @author Jeremy Pry + * + * @param int $post_id + * @deprecated 4.0.0 + */ + public static function save_coupon_fields( $post_id ) { + _deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::save_coupon_fields( $post_id ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + WCS_Limited_Recurring_Coupon_Manager::save_coupon_fields( $post_id ); + } + } + + /** + * Determine how many subscriptions the coupon has been applied to. + * + * @author Jeremy Pry + * + * @param WC_Subscription $subscription The current subscription. + * @deprecated 4.0.0 + */ + public static function check_coupon_usages( $subscription ) { + _deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::check_coupon_usages( $subscription ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + WCS_Limited_Recurring_Coupon_Manager::check_coupon_usages( $subscription ); + } + } + + /** + * Add our limited coupon data to the Coupon list table. + * + * @author Jeremy Pry + * + * @param string $column_name The name of the current column in the table. + * @param int $post_id The coupon post ID. + * @deprecated 4.0.0 + */ + public static function add_limit_to_list_table( $column_name, $post_id ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::add_limit_to_list_table( $column_name, $post_id ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + WCS_Limited_Recurring_Coupon_Manager::add_limit_to_list_table( $column_name, $post_id ); + } + } + + /** + * Filter the available gateways when there is a recurring coupon. + * + * @author Jeremy Pry + * + * @param WC_Payment_Gateway[] $gateways The available payment gateways. + * + * @return array The filtered payment gateways. + * @deprecated 4.0.0 + */ + public static function gateways_subscription_amount_changes( $gateways ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::gateways_subscription_amount_changes( $gateways ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + return WCS_Limited_Recurring_Coupon_Manager::gateways_subscription_amount_changes( $gateways ); + } + + return $gateways; + } + + /** + * Filter the message for when no payment gateways are available. + * + * @author Jeremy Pry + * + * @param string $message The current message indicating there are no payment methods available.. + * + * @return string The filtered message indicating there are no payment methods available. + * @deprecated 4.0.0 + */ + public static function no_available_payment_methods_message( $message ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::no_available_payment_methods_message() if available' ); + return __( 'Sorry, it seems there are no available payment methods which support the recurring coupon you are using. Please contact us if you require assistance or wish to make alternate arrangements.', 'woocommerce-subscriptions' ); + } + + /** + * Determine if a given coupon is limited to a certain number of renewals. + * + * @author Jeremy Pry + * + * @param string $code The coupon code. + * + * @return bool + * @deprecated 4.0.0 + */ + public static function coupon_is_limited( $code ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::coupon_is_limited() if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + return WCS_Limited_Recurring_Coupon_Manager::coupon_is_limited( $code ); + } + + return false; + } + + /** + * Determine whether the cart contains a recurring coupon with set number of renewals. + * + * @author Jeremy Pry + * @return bool + * @deprecated 4.0.0 + */ + public static function cart_contains_limited_recurring_coupon() { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::cart_contains_limited_recurring_coupon() if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + return WCS_Limited_Recurring_Coupon_Manager::cart_contains_limited_recurring_coupon(); + } + + return false; + } + + /** + * Determine if a given order has a limited use coupon. + * + * @author Jeremy Pry + * + * @param WC_Order|WC_Subscription $order + * + * @return bool + * @deprecated 4.0.0 + */ + public static function order_has_limited_recurring_coupon( $order ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::order_has_limited_recurring_coupon( $order ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + return WCS_Limited_Recurring_Coupon_Manager::order_has_limited_recurring_coupon( $order ); + } + + return false; + } + + /** + * Get the number of renewals for a limited coupon. + * + * @author Jeremy Pry + * + * @param string $code The coupon code. + * + * @return false|int False for non-recurring coupons, or the limit number for recurring coupons. + * A value of 0 is for unlimited usage. + * @deprecated 4.0.0 + */ + public static function get_coupon_limit( $code ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::get_coupon_limit( $code ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + return WCS_Limited_Recurring_Coupon_Manager::get_coupon_limit( $code ); + } + + return false; + } + + /** + * Determine if a given recurring cart contains a limited use coupon which when applied to a subscription will reach its usage limit within the subscription's length. + * + * @param WC_Cart $recurring_cart The recurring cart object. + * @return bool + * @deprecated 4.0.0 + */ + public static function recurring_cart_contains_expiring_coupon( $recurring_cart ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Limited_Recurring_Coupon_Manager::recurring_cart_contains_expiring_coupon( $recurring_cart ) if available' ); + if ( class_exists( 'WCS_Limited_Recurring_Coupon_Manager' ) ) { + return WCS_Limited_Recurring_Coupon_Manager::recurring_cart_contains_expiring_coupon( $recurring_cart ); + } + + return false; + } } diff --git a/includes/class-wc-subscriptions-email.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php similarity index 97% rename from includes/class-wc-subscriptions-email.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php index 3177701..9417e60 100644 --- a/includes/class-wc-subscriptions-email.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php @@ -81,7 +81,7 @@ class WC_Subscriptions_Email { ); // Don't send subscriptions emails or WC core emails for subscription-related events on staging sites. - if ( WC_Subscriptions::is_duplicate_site() && ! defined( 'WCS_FORCE_EMAIL' ) ) { + if ( WCS_Staging::is_duplicate_site() && ! defined( 'WCS_FORCE_EMAIL' ) ) { // Unhook WC order core emails which would normally be replaced by a subscription version on a live site. foreach ( $order_email_actions as $action ) { add_action( $action, __CLASS__ . '::maybe_remove_woocommerce_email', 9 ); @@ -288,7 +288,7 @@ class WC_Subscriptions_Email { 'order_items_table_args' => $order_items_table_args, ), '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' + WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } @@ -324,7 +324,7 @@ class WC_Subscriptions_Email { $hook = current_filter(); } - if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) && apply_filters( 'woocommerce_defer_transactional_emails', false ) ) { + if ( false === wcs_is_woocommerce_pre( '3.0' ) && apply_filters( 'woocommerce_defer_transactional_emails', false ) ) { add_action( $hook, array( 'WC_Emails', 'queue_transactional_email' ), $priority, $accepted_args ); } else { add_action( $hook, array( 'WC_Emails', 'send_transactional_email' ), $priority, $accepted_args ); diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php new file mode 100644 index 0000000..0574d1c --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php @@ -0,0 +1,617 @@ +get( Automattic\WooCommerce\StoreApi\SchemaController::class ) : Package::container()->get( Automattic\WooCommerce\Blocks\StoreApi\SchemaController::class ); + self::$money_formatter = function_exists( 'woocommerce_store_api_get_formatter' ) ? woocommerce_store_api_get_formatter( 'money' ) : Package::container()->get( ExtendRestApi::class )->get_formatter( 'money' ); + self::$currency_formatter = function_exists( 'woocommerce_store_api_get_formatter' ) ? woocommerce_store_api_get_formatter( 'currency' ) : Package::container()->get( ExtendRestApi::class )->get_formatter( 'currency' ); + self::extend_store(); + } + + /** + * Register endpoint data with the API. + * + * @param array $args Endpoint data to register. + */ + protected static function register_endpoint_data( $args ) { + if ( function_exists( 'woocommerce_store_api_register_endpoint_data' ) ) { + woocommerce_store_api_register_endpoint_data( $args ); + } else { + Package::container()->get( ExtendRestApi::class )->register_endpoint_data( $args ); + } + } + + /** + * Register payment requirements with the API. + * + * @param array $args Data to register. + */ + protected static function register_payment_requirements( $args ) { + if ( function_exists( 'woocommerce_store_api_register_payment_requirements' ) ) { + woocommerce_store_api_register_payment_requirements( $args ); + } else { + Package::container()->get( ExtendRestApi::class )->register_payment_requirements( $args ); + } + } + + /** + * Registers the actual data into each endpoint. + */ + public static function extend_store() { + // Register into `cart/items` + self::register_endpoint_data( + array( + 'endpoint' => CartItemSchema::IDENTIFIER, + 'namespace' => self::IDENTIFIER, + 'data_callback' => array( 'WC_Subscriptions_Extend_Store_Endpoint', 'extend_cart_item_data' ), + 'schema_callback' => array( 'WC_Subscriptions_Extend_Store_Endpoint', 'extend_cart_item_schema' ), + 'schema_type' => ARRAY_A, + ) + ); + + // Register into `cart` + self::register_endpoint_data( + array( + 'endpoint' => CartSchema::IDENTIFIER, + 'namespace' => self::IDENTIFIER, + 'data_callback' => array( 'WC_Subscriptions_Extend_Store_Endpoint', 'extend_cart_data' ), + 'schema_callback' => array( 'WC_Subscriptions_Extend_Store_Endpoint', 'extend_cart_schema' ), + 'schema_type' => ARRAY_N, + ) + ); + + // Register payment requirements. + self::register_payment_requirements( + array( + 'data_callback' => array( WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(), 'inject_payment_feature_requirements_for_cart_api' ), + ) + ); + } + + /** + * Register subscription product data into cart/items endpoint. + * + * @param array $cart_item Current cart item data. + * + * @return array $item_data Registered data or empty array if condition is not satisfied. + */ + public static function extend_cart_item_data( $cart_item ) { + $product = $cart_item['data']; + $item_data = array( + 'billing_period' => null, + 'billing_interval' => null, + 'subscription_length' => null, + 'trial_length' => null, + 'trial_period' => null, + 'sign_up_fees' => null, + 'sign_up_fees_tax' => null, + 'is_resubscribe' => null, + 'switch_type' => null, + 'synchronization' => null, + + ); + + if ( WC_Subscriptions_Product::is_subscription( $product ) ) { + $item_data = array_merge( + array( + 'billing_period' => WC_Subscriptions_Product::get_period( $product ), + 'billing_interval' => (int) WC_Subscriptions_Product::get_interval( $product ), + 'subscription_length' => (int) WC_Subscriptions_Product::get_length( $product ), + 'trial_length' => (int) WC_Subscriptions_Product::get_trial_length( $product ), + 'trial_period' => WC_Subscriptions_Product::get_trial_period( $product ), + 'is_resubscribe' => isset( $cart_item['subscription_resubscribe'] ), + 'switch_type' => wcs_get_cart_item_switch_type( $cart_item ), + 'synchronization' => self::format_sync_data( $product ), + ), + self::format_sign_up_fees( $product ) + ); + } + + return $item_data; + } + + /** + * Register subscription product schema into cart/items endpoint. + * + * @return array Registered schema. + */ + public static function extend_cart_item_schema() { + return array( + 'billing_period' => array( + 'description' => __( 'Billing period for the subscription.', 'woocommerce-subscriptions' ), + 'type' => array( 'string', 'null' ), + 'enum' => array_keys( wcs_get_subscription_period_strings() ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'billing_interval' => array( + 'description' => __( 'The number of billing periods between subscription renewals.', 'woocommerce-subscriptions' ), + 'type' => array( 'integer', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'subscription_length' => array( + 'description' => __( 'Subscription Product length.', 'woocommerce-subscriptions' ), + 'type' => array( 'integer', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'trial_period' => array( + 'description' => __( 'Subscription Product trial period.', 'woocommerce-subscriptions' ), + 'type' => array( 'string', 'null' ), + 'enum' => array_keys( wcs_get_subscription_period_strings() ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'trial_length' => array( + 'description' => __( 'Subscription Product trial interval.', 'woocommerce-subscriptions' ), + 'type' => array( 'integer', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'sign_up_fees' => array( + 'description' => __( 'Subscription Product signup fees.', 'woocommerce-subscriptions' ), + 'type' => array( 'string', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'sign_up_fees_tax' => array( + 'description' => __( 'Subscription Product signup fees taxes.', 'woocommerce-subscriptions' ), + 'type' => array( 'string', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'is_resubscribe' => array( + 'description' => __( + 'Indicates whether this product is being used to resubscribe the customer to an existing, expired subscription.', + 'woocommerce-subscriptions' + ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'switch_type' => array( + 'description' => __( + 'Indicates whether this product a subscription update, downgrade, cross grade or none of the above.', + 'woocommerce-subscriptions' + ), + 'type' => array( 'string', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'synchronization' => array( + 'description' => __( 'Synchronization data for the subscription.', 'woocommerce-subscriptions' ), + 'type' => array( 'object', 'integer', 'null' ), + 'properties' => array( + 'day' => array( + 'description' => __( 'Synchronization day if subscription is annual.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + ), + 'month' => array( + 'description' => __( 'Synchronization month if subscription is annual.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + ), + ), + ), + ); + } + + /** + * Get packages from the recurring carts. + * + * @param string $cart_key Recurring cart key. + * @param array $cart Recurring cart data. + * @return array + */ + private static function get_packages_for_recurring_cart( $cart_key, $cart ) { + $packages_by_cart = WC_Subscriptions_Cart::get_recurring_shipping_packages(); + + if ( ! isset( $packages_by_cart[ $cart_key ] ) ) { + return array(); + } + + $packages = $packages_by_cart[ $cart_key ]; + + // Add extra package data to array. + if ( count( $packages ) ) { + $packages = array_map( + function( $key, $package, $index ) use ( $cart, $cart_key ) { + $package['package_id'] = isset( $package['package_id'] ) ? $package['package_id'] : $key; + $package['package_name'] = isset( $package['package_name'] ) ? $package['package_name'] : self::get_shipping_package_name( $package, $cart ); + return $package; + }, + array_keys( $packages ), + $packages, + range( 1, count( $packages ) ) + ); + } + + return $packages; + } + + /** + * Changes the shipping package name to add more meaningful information about it's content. + * + * @param array $package All shipping package data. + * @param array $cart Recurring cart data. + * @return string + */ + private static function get_shipping_package_name( $package, $cart ) { + $package_name = __( 'Shipping', 'woocommerce-subscriptions' ); + $interval = wcs_cart_pluck( $cart, 'subscription_period_interval', '' ); + $period = wcs_cart_pluck( $cart, 'subscription_period', '' ); + switch ( $period ) { + case 'year': + // translators: %d subscription interval. + $package_name = $interval > 1 ? sprintf( _n( 'Shipment every %d year', 'Shipment every %d years', $interval, 'woocommerce-subscriptions' ), $interval ) : __( 'Yearly Shipment', 'woocommerce-subscriptions' ); + break; + case 'month': + // translators: %d subscription interval. + $package_name = $interval > 1 ? sprintf( _n( 'Shipment every %d month', 'Shipment every %d months', $interval, 'woocommerce-subscriptions' ), $interval ) : __( 'Monthly Shipment', 'woocommerce-subscriptions' ); + break; + case 'week': + // translators: %d subscription interval. + $package_name = $interval > 1 ? sprintf( _n( 'Shipment every %d week', 'Shipment every %d weeks', $interval, 'woocommerce-subscriptions' ), $interval ) : __( 'Weekly Shipment', 'woocommerce-subscriptions' ); + break; + case 'day': + // translators: %d subscription interval. + $package_name = $interval > 1 ? sprintf( _n( 'Shipment every %d day', 'Shipment every %d days', $interval, 'woocommerce-subscriptions' ), $interval ) : __( 'Daily Shipment', 'woocommerce-subscriptions' ); + break; + } + return $package_name; + } + + /** + * Register future subscriptions into cart endpoint. + * + * @return array $future_subscriptions Registered data or empty array if condition is not satisfied. + */ + public static function extend_cart_data() { + // return early if we don't have any subscription. + if ( ! WC_Subscriptions_Cart::cart_contains_subscription() ) { + return array(); + } + + $future_subscriptions = array(); + + if ( ! empty( wc()->cart->recurring_carts ) ) { + foreach ( wc()->cart->recurring_carts as $cart_key => $cart ) { + $cart_item = current( $cart->cart_contents ); + $product = $cart_item['data']; + $shipping_packages = self::get_packages_for_recurring_cart( $cart_key, $cart ); + + $future_subscriptions[] = array( + 'key' => $cart_key, + 'next_payment_date' => $cart->next_payment_date ? date_i18n( wc_date_format(), wcs_date_to_time( get_date_from_gmt( $cart->next_payment_date ) ) ) : null, + 'billing_period' => WC_Subscriptions_Product::get_period( $product ), + 'billing_interval' => (int) WC_Subscriptions_Product::get_interval( $product ), + 'subscription_length' => (int) WC_Subscriptions_Product::get_length( $product ), + 'totals' => self::$currency_formatter->format( + array( + 'total_items' => self::$money_formatter->format( $cart->get_subtotal() ), + 'total_items_tax' => self::$money_formatter->format( $cart->get_subtotal_tax() ), + 'total_fees' => self::$money_formatter->format( $cart->get_fee_total() ), + 'total_fees_tax' => self::$money_formatter->format( $cart->get_fee_tax() ), + 'total_discount' => self::$money_formatter->format( $cart->get_discount_total() ), + 'total_discount_tax' => self::$money_formatter->format( $cart->get_discount_tax() ), + 'total_shipping' => self::$money_formatter->format( $cart->get_shipping_total() ), + 'total_shipping_tax' => self::$money_formatter->format( $cart->get_shipping_tax() ), + 'total_price' => self::$money_formatter->format( $cart->get_total( 'edit' ) ), + 'total_tax' => self::$money_formatter->format( $cart->get_total_tax() ), + 'tax_lines' => self::get_tax_lines( $cart ), + ) + ), + 'shipping_rates' => array_values( array_map( array( self::$schema->get( 'cart-shipping-rate' ), 'get_item_response' ), $shipping_packages ) ), + ); + } + } + + return $future_subscriptions; + } + + /** + * Format sign-up fees. + * + * @param \WC_Product $product current product. + * @return array + */ + private static function format_sign_up_fees( $product ) { + $fees_excluding_tax = wcs_get_price_excluding_tax( + $product, + array( + 'qty' => 1, + 'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ), + ) + ); + + $fees_including_tax = wcs_get_price_including_tax( + $product, + array( + 'qty' => 1, + 'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ), + ) + ); + + return array( + 'sign_up_fees' => self::$money_formatter->format( + $fees_excluding_tax + ), + 'sign_up_fees_tax' => self::$money_formatter->format( + $fees_including_tax + - $fees_excluding_tax + ), + + ); + } + + /** + * Format sync data to the correct so it either returns a day integer or an object of day and month. + * + * @param WC_Product_Subscription $product current cart item product. + * + * @return object|int|null synchronization_date; + */ + private static function format_sync_data( $product ) { + if ( ! WC_Subscriptions_Synchroniser::is_product_synced( $product ) ) { + return null; + } + + $payment_day = WC_Subscriptions_Synchroniser::get_products_payment_day( $product ); + + if ( ! is_array( $payment_day ) ) { + return (int) $payment_day; + } + + return (object) array( + 'month' => (int) $payment_day['month'], + 'day' => (int) $payment_day['day'], + ); + } + /** + * Register future subscriptions schema into cart endpoint. + * + * @return array Registered schema. + */ + public static function extend_cart_schema() { + // return early if we don't have any subscription. + if ( ! WC_Subscriptions_Cart::cart_contains_subscription() ) { + return array(); + } + + return array( + 'key' => array( + 'description' => __( 'Subscription key', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'next_payment_date' => array( + 'description' => __( "The subscription's next payment date.", 'woocommerce-subscriptions' ), + 'type' => [ 'date-time', 'null' ], + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'billing_period' => array( + 'description' => __( 'Billing period for the subscription.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'enum' => array_keys( wcs_get_subscription_period_strings() ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'billing_interval' => array( + 'description' => __( 'The number of billing periods between subscription renewals.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'subscription_length' => array( + 'description' => __( 'Subscription length.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'totals' => array( + 'description' => __( 'Cart total amounts provided using the smallest unit of the currency.', 'woocommerce-subscriptions' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'properties' => array( + 'total_items' => array( + 'description' => __( 'Total price of items in the cart.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_items_tax' => array( + 'description' => __( 'Total tax on items in the cart.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_fees' => array( + 'description' => __( 'Total price of any applied fees.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_fees_tax' => array( + 'description' => __( 'Total tax on fees.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_discount' => array( + 'description' => __( 'Total discount from applied coupons.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_discount_tax' => array( + 'description' => __( 'Total tax removed due to discount from applied coupons.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_shipping' => array( + 'description' => __( 'Total price of shipping. If shipping has not been calculated, a null response will be sent.', 'woocommerce-subscriptions' ), + 'type' => array( 'string', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_shipping_tax' => array( + 'description' => __( 'Total tax on shipping. If shipping has not been calculated, a null response will be sent.', 'woocommerce-subscriptions' ), + 'type' => array( 'string', 'null' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_price' => array( + 'description' => __( 'Total price the customer will pay.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'total_tax' => array( + 'description' => __( 'Total tax applied to items and shipping.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'tax_lines' => array( + 'description' => __( 'Lines of taxes applied to items and shipping.', 'woocommerce-subscriptions' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'name' => array( + 'description' => __( 'The name of the tax.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'price' => array( + 'description' => __( 'The amount of tax charged.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ), + ), + 'currency_code' => array( + 'description' => __( 'Currency code (in ISO format) for returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'currency_symbol' => array( + 'description' => __( 'Currency symbol for the currency which can be used to format returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'currency_minor_unit' => array( + 'description' => __( 'Currency minor unit (number of digits after the decimal separator) for returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'currency_decimal_separator' => array( + 'description' => __( 'Decimal separator for the currency which can be used to format returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'currency_thousand_separator' => array( + 'description' => __( 'Thousand separator for the currency which can be used to format returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'currency_prefix' => array( + 'description' => __( 'Price prefix for the currency which can be used to format returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'currency_suffix' => array( + 'description' => __( 'Price prefix for the currency which can be used to format returned prices.', 'woocommerce-subscriptions' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ), + ); + } + + /** + * Get tax lines from the cart and format to match schema. + * + * TODO: This function is copied from WooCommerce Blocks, remove it once https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/3264 is closed. + * + * @param \WC_Cart $cart Cart class instance. + * @return array + */ + protected static function get_tax_lines( $cart ) { + $cart_tax_totals = $cart->get_tax_totals(); + $tax_lines = array(); + + foreach ( $cart_tax_totals as $cart_tax_total ) { + $tax_lines[] = array( + 'name' => $cart_tax_total->label, + 'price' => self::$money_formatter->format( $cart_tax_total->amount ), + ); + } + + return $tax_lines; + } +} diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-frontend-scripts.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-frontend-scripts.php new file mode 100644 index 0000000..735a460 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-frontend-scripts.php @@ -0,0 +1,88 @@ +get_subscriptions_core_directory_url( $file_relative_url ); + } + + /** + * Enqueues scripts for frontend. + * + * @since 3.1.3 + */ + public static function enqueue_scripts() { + $dependencies = array( 'jquery' ); + + if ( is_cart() || is_checkout() ) { + wp_enqueue_script( 'wcs-cart', self::get_file_url( 'assets/js/frontend/wcs-cart.js' ), $dependencies, WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(), true ); + } elseif ( is_product() ) { + wp_enqueue_script( 'wcs-single-product', self::get_file_url( 'assets/js/frontend/single-product.js' ), $dependencies, WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(), true ); + } elseif ( wcs_is_view_subscription_page() ) { + $subscription = wcs_get_subscription( absint( get_query_var( 'view-subscription' ) ) ); + + if ( $subscription && current_user_can( 'view_order', $subscription->get_id() ) ) { + $dependencies[] = 'jquery-blockui'; + $script_params = array( + 'ajax_url' => esc_url( WC()->ajax_url() ), + 'subscription_id' => $subscription->get_id(), + 'add_payment_method_msg' => __( 'To enable automatic renewals for this subscription, you will first need to add a payment method.', 'woocommerce-subscriptions' ) . "\n\n" . __( 'Would you like to add a payment method now?', 'woocommerce-subscriptions' ), + 'auto_renew_nonce' => WCS_My_Account_Auto_Renew_Toggle::can_user_toggle_auto_renewal( $subscription ) ? wp_create_nonce( "toggle-auto-renew-{$subscription->get_id()}" ) : false, + 'add_payment_method_url' => esc_url( $subscription->get_change_payment_method_url() ), + 'has_payment_gateway' => $subscription->has_payment_gateway() && wc_get_payment_gateway_by_order( $subscription )->supports( 'subscriptions' ), + ); + + wp_enqueue_script( 'wcs-view-subscription', self::get_file_url( 'assets/js/frontend/view-subscription.js' ), $dependencies, WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(), true ); + wp_localize_script( 'wcs-view-subscription', 'WCSViewSubscription', apply_filters( 'woocommerce_subscriptions_frontend_view_subscription_script_parameters', $script_params ) ); + } + } + } + + /** + * Enqueues stylesheets. + * + * @since 3.1.3 + */ + public static function enqueue_styles( $styles ) { + + if ( is_checkout() || is_cart() ) { + $styles['wcs-checkout'] = array( + 'src' => str_replace( array( 'http:', 'https:' ), '', self::get_file_url( 'assets/css/checkout.css' ) ), + 'deps' => 'wc-checkout', + 'version' => WC_VERSION, + 'media' => 'all', + ); + } elseif ( is_account_page() ) { + $styles['wcs-view-subscription'] = array( + 'src' => str_replace( array( 'http:', 'https:' ), '', self::get_file_url( 'assets/css/view-subscription.css' ) ), + 'deps' => 'woocommerce-smallscreen', + 'version' => WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(), + 'media' => 'all', + ); + } + + return $styles; + } +} diff --git a/includes/class-wc-subscriptions-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php similarity index 98% rename from includes/class-wc-subscriptions-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php index de54368..b529710 100644 --- a/includes/class-wc-subscriptions-manager.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php @@ -185,7 +185,9 @@ class WC_Subscriptions_Manager { $subscription = wcs_get_subscription( $subscription_id ); } - $subscription->update_status( 'cancelled' ); + if ( $subscription ) { + $subscription->update_status( 'cancelled' ); + } } /** @@ -406,7 +408,7 @@ class WC_Subscriptions_Manager { if ( ! empty( $subscriptions ) ) { if ( ! is_object( $order ) ) { - $order = new WC_Order( $order ); + $order = wc_get_order( $order ); } // Set subscription status to failed and log failure @@ -792,8 +794,7 @@ class WC_Subscriptions_Manager { * @since 1.0 */ public static function maybe_trash_subscription( $post_id ) { - - if ( 'shop_order' == get_post_type( $post_id ) ) { + if ( 'shop_order' === WC_Data_Store::load( 'order' )->get_order_type( $post_id ) ) { // delete subscription foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'parent' ) ) as $subscription ) { @@ -808,7 +809,7 @@ class WC_Subscriptions_Manager { * @since 2.2.17 */ public static function maybe_untrash_subscription( $post_id ) { - if ( 'shop_order' == get_post_type( $post_id ) ) { + if ( 'shop_order' === WC_Data_Store::load( 'order' )->get_order_type( $post_id ) ) { foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'parent', 'subscription_status' => array( 'trash' ) ) ) as $subscription ) { // phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound wp_untrash_post( $subscription->get_id() ); } @@ -823,7 +824,7 @@ class WC_Subscriptions_Manager { * @param int $post_id The post ID being deleted. */ public static function maybe_delete_subscription( $post_id ) { - if ( 'shop_order' !== get_post_type( $post_id ) ) { + if ( 'shop_order' !== WC_Data_Store::load( 'order' )->get_order_type( $post_id ) ) { return; } @@ -897,12 +898,25 @@ class WC_Subscriptions_Manager { * @since 2.0 */ public static function trash_users_subscriptions( $user_id ) { - $subscriptions = wcs_get_users_subscriptions( $user_id ); + $current_user = is_user_logged_in() ? wp_get_current_user() : null; if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { + $subscription_number = $subscription->get_order_number(); + + // Before deleting the subscription, add an order note to the related orders. + foreach ( $subscription->get_related_orders( 'all', array( 'parent', 'renewal', 'switch' ) ) as $order ) { + if ( $current_user ) { + // Translators: 1: The subscription ID number. 2: The current user's username. + $order->add_order_note( sprintf( __( 'The related subscription #%1$s has been deleted after the customer was deleted by %2$s.', 'woocommerce-subscriptions' ), $subscription_number, $current_user->display_name ) ); + } else { + // Translators: Placeholder is the subscription ID number. + $order->add_order_note( sprintf( __( 'The related subscription #%s has been deleted after the customer was deleted.', 'woocommerce-subscriptions' ), $subscription_number ) ); + } + } + wp_delete_post( $subscription->get_id() ); } } diff --git a/includes/class-wc-subscriptions-order.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php similarity index 95% rename from includes/class-wc-subscriptions-order.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php index 170450a..58245d0 100644 --- a/includes/class-wc-subscriptions-order.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php @@ -93,7 +93,7 @@ class WC_Subscriptions_Order { public static function get_non_subscription_total( $order ) { if ( ! is_object( $order ) ) { - $order = new WC_Order( $order ); + $order = wc_get_order( $order ); } $non_subscription_total = 0; @@ -166,7 +166,7 @@ class WC_Subscriptions_Order { public static function get_item_by_product_id( $order, $product_id = '' ) { if ( ! is_object( $order ) ) { - $order = new WC_Order( $order ); + $order = wc_get_order( $order ); } foreach ( $order->get_items() as $item ) { @@ -237,7 +237,7 @@ class WC_Subscriptions_Order { WHERE order_item_id = %d ", $order_item_id ), ARRAY_A ); - $order = new WC_Order( absint( $item['order_id'] ) ); + $order = wc_get_order( absint( $item['order_id'] ) ); $item['name'] = $item['order_item_name']; $item['type'] = $item['order_item_type']; @@ -324,40 +324,6 @@ class WC_Subscriptions_Order { } } - /** - * A unified API for accessing subscription order meta, especially for sign-up fee related order meta. - * - * Because WooCommerce 2.1 deprecated WC_Order::$order_custom_fields, this function is also used to provide - * version independent meta data access to non-subscription meta data. - * - * @param WC_Order|int $order The WC_Order object or ID of the order for which the meta should be sought. - * @param string $meta_key The key as stored in the post meta table for the meta item. - * @param mixed $default (optional) The default value to return if the meta key does not exist. Default 0. - * @since 1.0 - */ - public static function get_meta( $order, $meta_key, $default = 0 ) { - - if ( ! is_object( $order ) ) { - $order = new WC_Order( $order ); - } - - $meta_key = preg_replace( '/^_/', '', $meta_key ); - - if ( isset( $order->$meta_key ) ) { // WC 2.1+ magic __isset() & __get() methods - $meta_value = $order->$meta_key; - } elseif ( is_array( $order->order_custom_fields ) && isset( $order->order_custom_fields[ '_' . $meta_key ][0] ) && $order->order_custom_fields[ '_' . $meta_key ][0] ) { // < WC 2.1+ - $meta_value = maybe_unserialize( $order->order_custom_fields[ '_' . $meta_key ][0] ); - } else { - $meta_value = get_post_meta( wcs_get_objects_property( $order, 'id' ), '_' . $meta_key, true ); - - if ( empty( $meta_value ) ) { - $meta_value = $default; - } - } - - return $meta_value; - } - /** * Displays a few details about what happens to their subscription. Hooked * to the thank you page. @@ -501,6 +467,24 @@ class WC_Subscriptions_Order { $order_completed = in_array( $new_order_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ) && in_array( $old_order_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); foreach ( $subscriptions as $subscription ) { + // A special case where payment completes after user cancels subscription + if ( $order_completed && $subscription->has_status( 'cancelled' ) ) { + + // Store the actual cancelled_date so as to restore it after it is rewritten by update_status() + $cancelled_date = $subscription->get_date( 'cancelled' ); + + // Force set cancelled_date and end date to 0 temporarily so that next_payment_date can be calculated properly + // This next_payment_date will be the end of prepaid term that will be picked by action scheduler + $subscription->update_dates( array( 'cancelled' => 0, 'end' => 0 ) ); + + $next_payment_date = $subscription->calculate_date( 'next_payment' ); + $subscription->update_dates( array( 'next_payment' => $next_payment_date ) ); + + $subscription->update_status( 'pending-cancel', __( 'Payment completed on order after subscription was cancelled.', 'woocommerce-subscriptions' ) ); + + // Restore the actual cancelled date + $subscription->update_dates( array( 'cancelled' => $cancelled_date ) ); + } // Do we need to activate a subscription? if ( $order_completed && ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) && ! $subscription->has_status( 'active' ) ) { @@ -604,26 +588,35 @@ class WC_Subscriptions_Order { } // Get all the customers orders which are not subscription renewal orders - $order_ids = get_posts( array( - 'posts_per_page' => 1, - 'post_type' => 'shop_order', - 'post_status' => 'any', - 'fields' => 'ids', - 'orderby' => 'date', - 'order' => 'DESC', - 'meta_query' => array( - array( - 'key' => '_customer_user', - 'compare' => '=', - 'value' => $user_id, - 'type' => 'numeric', - ), - array( + $custom_query_var_handler = function( $query, $query_vars ) { + if ( ! empty( $query_vars['_non_subscription_renewal'] ) ) { + $query['meta_query'][] = array( 'key' => '_subscription_renewal', 'compare' => 'NOT EXISTS', - ), - ), - ) ); + ); + unset( $query_vars['_non_subscription_renewal'] ); + } + + return $query; + }; + add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', $custom_query_var_handler, 10, 2 ); + + $all_possible_statuses = array_values( array_unique( array_keys( wc_get_order_statuses() ) ) ); + + $args = array( + 'type' => 'shop_order', + 'status' => $all_possible_statuses, + 'orderby' => 'date', + 'order' => 'DESC', + 'customer_id' => $user_id, + 'return' => 'ids', + ); + + $args['_non_subscription_renewal'] = true; + + $order_ids = wc_get_orders( $args ); + + remove_filter( 'woocommerce_order_data_store_cpt_get_orders_query', $custom_query_var_handler, 10 ); foreach ( $order_ids as $index => $order_id ) { if ( ! wcs_order_contains_subscription( $order_id, 'parent' ) ) { @@ -646,8 +639,39 @@ class WC_Subscriptions_Order { * @return bool */ public static function order_needs_payment( $needs_payment, $order, $valid_order_statuses ) { + // Skips checks if the order already needs payment. + if ( $needs_payment ) { + return $needs_payment; + } - if ( false === $needs_payment && 0 == $order->get_total() && in_array( $order->get_status(), $valid_order_statuses ) && wcs_order_contains_subscription( $order ) && self::get_recurring_total( $order ) > 0 && 'yes' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) { + // Skip checks if order doesn't contain a subscription product. + if ( ! wcs_order_contains_subscription( $order ) ) { + return $needs_payment; + } + + // Skip checks if order total is greater than zero, or + // recurring total is zero, or + // order status isn't valid for payment. + if ( $order->get_total() > 0 || self::get_recurring_total( $order ) <= 0 || ! $order->has_status( $valid_order_statuses ) ) { + return $needs_payment; + } + + // Check that there is at least 1 subscription with a next payment that would require a payment method. + $has_next_payment = false; + + foreach ( wcs_get_subscriptions_for_order( $order ) as $subscription ) { + if ( $subscription->get_time( 'next_payment' ) ) { + $has_next_payment = true; + break; + } + } + + if ( ! $has_next_payment ) { + return $needs_payment; + } + + // If manual renewals are not required. + if ( ! wcs_is_manual_renewal_required() ) { $needs_payment = true; } @@ -665,8 +689,8 @@ class WC_Subscriptions_Order { if ( ! empty( $subscriptions ) ) { - $template_base = plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/'; - $template = ( $plaintext ) ? 'emails/plain/subscription-info.php' : 'emails/subscription-info.php'; + $template_base = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ); + $template = ( $plaintext ) ? 'emails/plain/subscription-info.php' : 'emails/subscription-info.php'; wc_get_template( $template, @@ -803,7 +827,7 @@ class WC_Subscriptions_Order { 'subscriptions' => $subscriptions, ), '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' + WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } } @@ -825,7 +849,7 @@ class WC_Subscriptions_Order { 'subscription' => $subscription, ), '', - plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' + WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } } @@ -992,7 +1016,7 @@ class WC_Subscriptions_Order { public static function maybe_cancel_subscription_on_full_refund( $order ) { if ( ! is_object( $order ) ) { - $order = new WC_Order( $order ); + $order = wc_get_order( $order ); } if ( wcs_order_contains_subscription( $order, array( 'parent', 'renewal' ) ) ) { @@ -2172,4 +2196,41 @@ class WC_Subscriptions_Order { _deprecated_function( __METHOD__, '2.2.0', 'wcs_get_objects_property( $order, "currency" ) or $order->get_currency()' ); return wcs_get_objects_property( $order, 'currency' ); } + + /** + * A unified API for accessing subscription order meta, especially for sign-up fee related order meta. + * + * Because WooCommerce 2.1 deprecated WC_Order::$order_custom_fields, this function is also used to provide + * version independent meta data access to non-subscription meta data. + * + * Deprecated in Subscriptions Core 2.0 since we have the wcs_get_objects_property() which serves the same purpose. + * + * @deprecated 2.0 + * @since 1.0 + * + * @param WC_Order|int $order The WC_Order object or ID of the order for which the meta should be sought. + * @param string $meta_key The key as stored in the post meta table for the meta item. + * @param mixed $default The default value to return if the meta key does not exist. Default 0. + * + * @return mixed Order meta data found by key. + */ + public static function get_meta( $order, $meta_key, $default = 0 ) { + wcs_deprecated_function( __METHOD__, '2.0', 'wcs_get_objects_property( $order, $meta_key, "single", $default )' ); + + if ( ! is_object( $order ) ) { + $order = wc_get_order( $order ); + } + + $meta_key = preg_replace( '/^_/', '', $meta_key ); + + if ( isset( $order->$meta_key ) ) { // WC 2.1+ magic __isset() & __get() methods + $meta_value = $order->$meta_key; + } elseif ( is_array( $order->order_custom_fields ) && isset( $order->order_custom_fields[ '_' . $meta_key ][0] ) && $order->order_custom_fields[ '_' . $meta_key ][0] ) { // < WC 2.1+ + $meta_value = maybe_unserialize( $order->order_custom_fields[ '_' . $meta_key ][0] ); + } else { + $meta_value = wcs_get_objects_property( $order, $meta_key, 'single', $default ); + } + + return $meta_value; + } } diff --git a/includes/class-wc-subscriptions-product.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php similarity index 96% rename from includes/class-wc-subscriptions-product.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php index 6e7db14..ba6ac10 100644 --- a/includes/class-wc-subscriptions-product.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php @@ -75,6 +75,8 @@ class WC_Subscriptions_Product { // maybe update the One Time Shipping product setting when users edit variations using bulk actions and the variation level save add_action( 'wp_ajax_wcs_update_one_time_shipping', __CLASS__ . '::maybe_update_one_time_shipping_on_variation_edits' ); + + add_action( 'wp_ajax_wcs_validate_variation_deletion', array( __CLASS__, 'validate_variation_deletion' ) ); } /** @@ -242,6 +244,10 @@ class WC_Subscriptions_Product { $sign_up_fee = 0; $include_length = $include['subscription_length'] && 0 !== $subscription_length; + if ( empty( $billing_period ) ) { + $billing_period = 'month'; + } + if ( $include_length ) { $ranges = wcs_get_subscription_ranges( $billing_period ); } @@ -314,7 +320,7 @@ class WC_Subscriptions_Product { // translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month"). __( '%1$s on the %2$s of each month', 'woocommerce-subscriptions' ), $price, - WC_Subscriptions::append_numeral_suffix( $payment_day ) + wcs_append_numeral_suffix( $payment_day ) ); } } else { @@ -323,15 +329,15 @@ class WC_Subscriptions_Product { // translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month"). __( '%1$s on the last day of every %2$s month', 'woocommerce-subscriptions' ), $price, - WC_Subscriptions::append_numeral_suffix( $billing_interval ) + wcs_append_numeral_suffix( $billing_interval ) ); } else { $subscription_string .= sprintf( // translators: 1$: on the, 2$: day of every, 3$: month (e.g. "$10 on the 23rd day of every 2nd month"). __( '%1$s on the %2$s day of every %3$s month', 'woocommerce-subscriptions' ), $price, - WC_Subscriptions::append_numeral_suffix( $payment_day ), - WC_Subscriptions::append_numeral_suffix( $billing_interval ) + wcs_append_numeral_suffix( $payment_day ), + wcs_append_numeral_suffix( $billing_interval ) ); } } @@ -343,7 +349,7 @@ class WC_Subscriptions_Product { __( '%1$s on %2$s %3$s each year', 'woocommerce-subscriptions' ), $price, $wp_locale->month[ $payment_day['month'] ], - WC_Subscriptions::append_numeral_suffix( $payment_day['day'] ) + wcs_append_numeral_suffix( $payment_day['day'] ) ); } else { $subscription_string .= sprintf( @@ -351,8 +357,8 @@ class WC_Subscriptions_Product { __( '%1$s on %2$s %3$s every %4$s year', 'woocommerce-subscriptions' ), $price, $wp_locale->month[ $payment_day['month'] ], - WC_Subscriptions::append_numeral_suffix( $payment_day['day'] ), - WC_Subscriptions::append_numeral_suffix( $billing_interval ) + wcs_append_numeral_suffix( $payment_day['day'] ), + wcs_append_numeral_suffix( $billing_interval ) ); } break; @@ -435,7 +441,7 @@ class WC_Subscriptions_Product { */ public static function get_regular_price( $product, $context = 'view' ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $regular_price = $product->regular_price; } else { $regular_price = $product->get_regular_price( $context ); @@ -453,7 +459,7 @@ class WC_Subscriptions_Product { */ public static function get_sale_price( $product, $context = 'view' ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $sale_price = $product->sale_price; } else { $sale_price = $product->get_sale_price( $context ); @@ -956,14 +962,20 @@ class WC_Subscriptions_Product { * @since 2.2.17 */ public static function add_variation_removal_flag( $loop, $variation_data, $variation ) { - $related_subscriptions = wcs_get_subscriptions_for_product( $variation->ID ); - $can_remove = empty( $related_subscriptions ); + + // On large sites we validate the request on submit, rather than on page load to avoid performance hits caused by wcs_get_subscriptions_for_product(). + if ( wcs_is_large_site() ) { + $can_remove = false; + } else { + $related_subscriptions = wcs_get_subscriptions_for_product( $variation->ID, 'ids', array( 'limit' => 1 ) ); + $can_remove = empty( $related_subscriptions ); + } printf( '', intval( $can_remove ) ); if ( ! $can_remove ) { - $msg = __( 'This variation can not be removed because it is associated with active subscriptions. To remove this variation, please cancel and delete the subscriptions for it.', 'woocommerce-subscriptions' ); - printf( '', wc_sanitize_tooltip( $msg ) ); // XSS ok. + $msg = __( 'This variation can not be removed because it is associated with existing subscriptions. To remove this variation, please permanently delete any related subscriptions.', 'woocommerce-subscriptions' ); + printf( '', wc_sanitize_tooltip( $msg ), absint( $variation->ID ) ); // XSS ok. } } @@ -1144,7 +1156,7 @@ class WC_Subscriptions_Product { global $wpdb; $parent_product_ids = array(); - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) && isset( $product->post->post_parent ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) && isset( $product->post->post_parent ) ) { $parent_product_ids[] = $product->get_parent(); } else { $parent_product_ids = $wpdb->get_col( $wpdb->prepare( @@ -1189,7 +1201,21 @@ class WC_Subscriptions_Product { * @return string The add to cart text. */ public static function get_add_to_cart_text() { - return get_option( WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text', __( 'Sign up now', 'woocommerce-subscriptions' ) ); + return apply_filters( 'wc_subscription_product_add_to_cart_text', __( 'Sign up now', 'woocommerce-subscriptions' ) ); + } + + /** + * Validates an ajax request to delete a subscription variation. + * + * @since 3.x.x + */ + public static function validate_variation_deletion() { + check_admin_referer( 'wc_subscriptions_admin', 'nonce' ); + + $variation_id = absint( $_POST['variation_id'] ); + $subscriptions = wcs_get_subscriptions_for_product( $variation_id, 'ids', array( 'limit' => 1 ) ); + + wp_send_json( array( 'can_remove' => empty( $subscriptions ) ? 'yes' : 'no' ) ); } /************************ diff --git a/includes/class-wc-subscriptions-renewal-order.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php similarity index 99% rename from includes/class-wc-subscriptions-renewal-order.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php index 31dff26..6f6e0dd 100644 --- a/includes/class-wc-subscriptions-renewal-order.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php @@ -85,7 +85,7 @@ class WC_Subscriptions_Renewal_Order { if ( $order_completed && $order_needed_payment ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $update_post_data = array( 'ID' => $order_id, 'post_date' => current_time( 'mysql', 0 ), diff --git a/includes/class-wc-subscriptions-synchroniser.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php similarity index 97% rename from includes/class-wc-subscriptions-synchroniser.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php index 29cdb14..be95b25 100644 --- a/includes/class-wc-subscriptions-synchroniser.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php @@ -98,7 +98,7 @@ class WC_Subscriptions_Synchroniser { // When adding an item to a subscription, check if it is for a synced product to make sure the sync meta is set on the subscription. We can't attach to just the 'woocommerce_new_order_item' here because the '_product_id' and '_variation_id' meta are not set before it fires add_action( 'woocommerce_ajax_add_order_item_meta', __CLASS__ . '::ajax_maybe_add_meta_for_item', 10, 2 ); - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { add_action( 'woocommerce_order_add_product', __CLASS__ . '::maybe_add_meta_for_new_product', 10, 3 ); add_action( 'woocommerce_add_order_item_meta', array( __CLASS__, 'maybe_add_order_item_meta' ), 10, 2 ); } else { @@ -194,18 +194,7 @@ class WC_Subscriptions_Synchroniser { * @since 1.5 */ public static function add_settings( $settings ) { - - // Get the index of the setting. - $index = 0; - foreach ( $settings as $i => $setting ) { - if ( 'title' == $setting['type'] && 'woocommerce_subscriptions_miscellaneous' == $setting['id'] ) { - $index = $i; - break; - } - } - - array_splice( $settings, $index, 0, array( - + $synchronisation_settings = array( array( 'name' => __( 'Synchronisation', 'woocommerce-subscriptions' ), 'type' => 'title', @@ -251,7 +240,12 @@ class WC_Subscriptions_Synchroniser { 'type' => 'sectionend', 'id' => self::$setting_id . '_title', ), - ) ); + ); + + // Insert the switch settings in after the Roles section otherwise add the settings to the end. + if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_role_options', $synchronisation_settings, 'multiple-settings', 'sectionend' ) ) { + $settings = array_merge( $settings, $synchronisation_settings ); + } return $settings; } @@ -356,7 +350,7 @@ class WC_Subscriptions_Synchroniser { $payment_month = 0; } - include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/html-variation-synchronisation.php' ); + include( WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/html-variation-synchronisation.php' ) ); } } @@ -778,7 +772,7 @@ class WC_Subscriptions_Synchroniser { // Month foreach ( range( 1, 27 ) as $i ) { // translators: placeholder is a number of day with language specific suffix applied (e.g. "1st", "3rd", "5th", etc...) - self::$billing_period_ranges['month'][ $i ] = sprintf( __( '%s day of the month', 'woocommerce-subscriptions' ), WC_Subscriptions::append_numeral_suffix( $i ) ); + self::$billing_period_ranges['month'][ $i ] = sprintf( __( '%s day of the month', 'woocommerce-subscriptions' ), wcs_append_numeral_suffix( $i ) ); } self::$billing_period_ranges['month'][28] = __( 'Last day of the month', 'woocommerce-subscriptions' ); @@ -883,7 +877,8 @@ class WC_Subscriptions_Synchroniser { self::is_product_synced( $cart_item['data'] ) && ! self::is_payment_upfront( $cart_item['data'] ) && ! self::is_product_prorated( $cart_item['data'] ) && - ! self::is_today( self::calculate_first_payment_date( $cart_item['data'], 'timestamp' ) ) + ! self::is_today( self::calculate_first_payment_date( $cart_item['data'], 'timestamp' ) ) && + ( ! isset( $cart_item['subscription_resubscribe'] ) || ! self::is_sync_proration_enabled() ) // Dont override trial length set while resubscribing unless proration is disabled. ) { $current_trial_length = WC_Subscriptions_Product::get_trial_length( WC()->cart->cart_contents[ $cart_item_key ]['data'] ); $new_trial_length = ( $current_trial_length > 1 ) ? $current_trial_length : 1; @@ -902,8 +897,17 @@ class WC_Subscriptions_Synchroniser { public static function maybe_unset_free_trial( $total = '' ) { foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( self::is_product_synced( $cart_item['data'] ) ) { - wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', WC_Subscriptions_Product::get_trial_length( wcs_get_canonical_product_id( $cart_item ) ), 'set_prop_only' ); + // Dont override trial length set while resubscribing, unless proration is disabled. + if ( self::is_product_synced( $cart_item['data'] ) && ( ! isset( $cart_item['subscription_resubscribe'] ) || ! self::is_sync_proration_enabled() ) ) { + + // When reinstating the trial length, set resubscribes trial length to 0 so we don't grant a second trial period. + if ( isset( $cart_item['subscription_resubscribe'] ) ) { + $trial_length = 0; + } else { + $trial_length = WC_Subscriptions_Product::get_trial_length( wcs_get_canonical_product_id( $cart_item ) ); + } + + wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', $trial_length, 'set_prop_only' ); } } return $total; diff --git a/includes/class-wc-subscriptions-tracker.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-tracker.php similarity index 97% rename from includes/class-wc-subscriptions-tracker.php rename to vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-tracker.php index b5c5dd1..bab628b 100644 --- a/includes/class-wc-subscriptions-tracker.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-tracker.php @@ -44,8 +44,8 @@ class WC_Subscriptions_Tracker { private static function get_subscriptions_options() { return array( // Staging and live site - 'wc_subscriptions_staging' => WC_Subscriptions::is_duplicate_site() ? 'staging' : 'live', - 'wc_subscriptions_live_url' => esc_url( WC_Subscriptions::get_site_url_from_source( 'subscriptions_install' ) ), + 'wc_subscriptions_staging' => WCS_Staging::is_duplicate_site() ? 'staging' : 'live', + 'wc_subscriptions_live_url' => esc_url( WCS_Staging::get_site_url_from_source( 'subscriptions_install' ) ), // Button text, roles 'add_to_cart_button_text' => get_option( WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text' ), diff --git a/includes/class-wcs-action-scheduler.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-action-scheduler.php similarity index 100% rename from includes/class-wcs-action-scheduler.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-action-scheduler.php diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wcs-blocks-integration.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-blocks-integration.php new file mode 100644 index 0000000..ebd48db --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-blocks-integration.php @@ -0,0 +1,100 @@ +get_subscriptions_core_directory_url( $script_path ); + $style_url = \WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( $style_path ); + + $script_asset_path = \WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'build/index.asset.php' ); + $script_asset = file_exists( $script_asset_path ) + ? require $script_asset_path + : array( + 'dependencies' => array(), + 'version' => $this->get_file_version( $script_asset_path ), + ); + + wp_register_script( + 'wc-blocks-integration', + $script_url, + $script_asset['dependencies'], + $script_asset['version'], + true + ); + wp_set_script_translations( + 'wc-blocks-integration', + 'woocommerce-subscriptions', + \WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'languages' ) + ); + wp_enqueue_style( + 'wc-blocks-integration', + $style_url, + '', + $this->get_file_version( \WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'build/index.css' ) ), + 'all' + ); + } + + /** + * Returns an array of script handles to enqueue in the frontend context. + * + * @return string[] + */ + public function get_script_handles() { + return array( 'wc-blocks-integration' ); + } + + /** + * Returns an array of script handles to enqueue in the editor context. + * + * @return string[] + */ + public function get_editor_script_handles() { + return array( 'wc-blocks-integration' ); + } + + /** + * An array of key, value pairs of data made available to the block on the client side. + * + * @return array + */ + public function get_script_data() { + return array( + 'woocommerce-subscriptions-blocks' => 'active', + ); + } + + /** + * Get the file modified time as a cache buster if we're in dev mode. + * + * @param string $file Local path to the file. + * @return string The cache buster value to use for the given file. + */ + protected function get_file_version( $file ) { + if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( $file ) ) { + return filemtime( $file ); + } + return \WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(); + } +} diff --git a/includes/class-wcs-cached-data-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php similarity index 99% rename from includes/class-wcs-cached-data-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php index f61a35c..1c02cf6 100644 --- a/includes/class-wcs-cached-data-manager.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cached-data-manager.php @@ -57,7 +57,7 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { // if there isn't a transient currently stored and we have a callback update function, fetch and store if ( false === $data && ! empty( $callback ) ) { - $data = call_user_func_array( $callback, $params ); + $data = call_user_func_array( $callback, array_values( $params ) ); set_transient( $key, $data, $expires ); } diff --git a/includes/class-wcs-cart-initial-payment.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-initial-payment.php similarity index 82% rename from includes/class-wcs-cart-initial-payment.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-initial-payment.php index c8025e9..8d6fee4 100644 --- a/includes/class-wcs-cart-initial-payment.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-initial-payment.php @@ -54,10 +54,13 @@ class WCS_Cart_Initial_Payment extends WCS_Cart_Renewal { if ( ! is_user_logged_in() ) { // Allow the customer to login first and then redirect them back. - $redirect = add_query_arg( array( - 'wcs_redirect' => 'pay_for_order', - 'wcs_redirect_id' => $order_id, - ), get_permalink( wc_get_page_id( 'myaccount' ) ) ); + $redirect = add_query_arg( + array( + 'wcs_redirect' => 'pay_for_order', + 'wcs_redirect_id' => $order_id, + ), + get_permalink( wc_get_page_id( 'myaccount' ) ) + ); } elseif ( ! current_user_can( 'pay_for_order', $order_id ) ) { wc_add_notice( __( 'That doesn\'t appear to be your order.', 'woocommerce-subscriptions' ), 'error' ); @@ -67,17 +70,17 @@ class WCS_Cart_Initial_Payment extends WCS_Cart_Renewal { do_action( 'wcs_before_parent_order_setup_cart', $subscriptions, $order ); // Add the existing order items to the cart - $this->setup_cart( $order, array( - 'order_id' => $order_id, - ) ); + $this->setup_cart( + $order, + array( + 'order_id' => $order_id, + ) + ); do_action( 'wcs_after_parent_order_setup_cart', $subscriptions, $order ); // Store order's ID in the session so it can be re-used after payment - WC()->session->set( 'order_awaiting_payment', $order_id ); - - $this->set_cart_hash( $order_id ); - + $this->set_order_awaiting_payment( $order_id ); $redirect = wc_get_checkout_url(); } @@ -130,4 +133,16 @@ class WCS_Cart_Initial_Payment extends WCS_Cart_Renewal { return $order; } + /** + * Deteremines if the cart should honor the granfathered subscription/order line item total. + * + * @since 3.0.10 + * + * @param array $cart_item The cart item to check. + * @return bool Whether the cart should honor the order's prices. + */ + public function should_honor_subscription_prices( $cart_item ) { + $order = $this->get_order( $cart_item ); + return $order && $order->meta_exists( '_manual_price_increases_locked' ); + } } diff --git a/includes/class-wcs-cart-renewal.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php similarity index 86% rename from includes/class-wcs-cart-renewal.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php index 6ebcfd1..ff21b55 100644 --- a/includes/class-wcs-cart-renewal.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php @@ -77,7 +77,7 @@ class WCS_Cart_Renewal { */ public function attach_dependant_hooks() { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { // When a renewal order's line items are being updated, update the line item IDs stored in cart data. add_action( 'woocommerce_add_order_item_meta', array( &$this, 'update_line_item_cart_data' ), 10, 3 ); @@ -92,11 +92,20 @@ class WCS_Cart_Renewal { // After order meta is saved, get the order line item ID for the renewal so we can update it later add_action( 'woocommerce_checkout_update_order_meta', array( &$this, 'set_order_item_id' ), 10, 2 ); + // After order meta is saved, get the order line item ID for the renewal so we can update it later + if ( version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '7.2.0', '>=' ) ) { + add_action( 'woocommerce_store_api_checkout_update_order_meta', array( &$this, 'set_order_item_id' ) ); + } else { + add_action( 'woocommerce_blocks_checkout_update_order_meta', array( &$this, 'set_order_item_id' ) ); + } + // Don't display cart item key meta stored above on the Edit Order screen add_action( 'woocommerce_hidden_order_itemmeta', array( &$this, 'hidden_order_itemmeta' ), 10 ); // Update customer's address on the subscription if it is changed during renewal add_filter( 'woocommerce_checkout_update_user_meta', array( &$this, 'maybe_update_subscription_address_data' ), 10, 2 ); + add_filter( 'woocommerce_store_api_checkout_update_customer_from_request', array( &$this, 'maybe_update_subscription_address_data_from_store_api' ), 10, 2 ); + } } @@ -141,6 +150,12 @@ class WCS_Cart_Renewal { // Attach hooks which depend on WooCommerce version constants. Differs from @see attach_dependant_hooks() in that this is hooked inside an inherited function and so extended classes will also inherit these callbacks add_action( 'woocommerce_loaded', array( &$this, 'attach_dependant_callbacks' ), 10 ); + + // Filters the Place order button text on checkout. + add_filter( 'woocommerce_order_button_text', array( $this, 'order_button_text' ), 15 ); + + // Before WC loads the cart from the session, verify if it belongs to the current user. + add_action( 'woocommerce_load_cart_from_session', array( $this, 'verify_session_belongs_to_customer' ) ); } /** @@ -150,7 +165,7 @@ class WCS_Cart_Renewal { */ public function attach_dependant_callbacks() { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { add_action( 'woocommerce_add_order_item_meta', array( &$this, 'add_order_item_meta' ), 10, 2 ); add_action( 'woocommerce_add_subscription_item_meta', array( &$this, 'add_order_item_meta' ), 10, 2 ); } else { @@ -166,33 +181,31 @@ class WCS_Cart_Renewal { * @since 2.0 */ public function maybe_setup_cart() { - global $wp; if ( isset( $_GET['pay_for_order'] ) && isset( $_GET['key'] ) && isset( $wp->query_vars['order-pay'] ) ) { // Pay for existing order $order_key = $_GET['key']; - $order_id = ( isset( $wp->query_vars['order-pay'] ) ) ? $wp->query_vars['order-pay'] : absint( $_GET['order_id'] ); - $order = wc_get_order( $wp->query_vars['order-pay'] ); + $order_id = isset( $wp->query_vars['order-pay'] ) ? $wp->query_vars['order-pay'] : absint( $_GET['order_id'] ); + $order = wc_get_order( $order_id ); - if ( wcs_get_objects_property( $order, 'order_key' ) == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_renewal( $order ) ) { + if ( wcs_get_objects_property( $order, 'order_key' ) === $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_renewal( $order ) ) { // If a user isn't logged in, allow them to login first and then redirect back if ( ! is_user_logged_in() ) { - - $redirect = add_query_arg( array( - 'wcs_redirect' => 'pay_for_order', - 'wcs_redirect_id' => $order_id, - ), get_permalink( wc_get_page_id( 'myaccount' ) ) ); + $redirect = add_query_arg( + array( + 'wcs_redirect' => 'pay_for_order', + 'wcs_redirect_id' => $order_id, + ), + get_permalink( wc_get_page_id( 'myaccount' ) ) + ); wp_safe_redirect( $redirect ); exit; - } elseif ( ! current_user_can( 'pay_for_order', $order_id ) ) { - wc_add_notice( __( 'That doesn\'t appear to be your order.', 'woocommerce-subscriptions' ), 'error' ); - wp_safe_redirect( get_permalink( wc_get_page_id( 'myaccount' ) ) ); exit; } @@ -210,10 +223,14 @@ class WCS_Cart_Renewal { wc_add_notice( __( 'This order can no longer be paid because the corresponding subscription does not require payment at this time.', 'woocommerce-subscriptions' ), 'error' ); } else { // Add the existing subscription items to the cart - $this->setup_cart( $order, array( - 'subscription_id' => $subscription->get_id(), - 'renewal_order_id' => $order_id, - ), 'all_items_required' ); + $this->setup_cart( + $order, + array( + 'subscription_id' => $subscription->get_id(), + 'renewal_order_id' => $order_id, + ), + 'all_items_required' + ); } do_action( 'wcs_after_renewal_setup_cart_subscription', $subscription, $order ); @@ -223,7 +240,7 @@ class WCS_Cart_Renewal { if ( WC()->cart->cart_contents_count != 0 ) { // Store renewal order's ID in session so it can be re-used after payment - WC()->session->set( 'order_awaiting_payment', $order_id ); + $this->set_order_awaiting_payment( $order_id ); wc_add_notice( __( 'Complete checkout to renew your subscription.', 'woocommerce-subscriptions' ), 'success' ); } @@ -233,6 +250,24 @@ class WCS_Cart_Renewal { } } + /** + * Updates the WooCommerce session variables so that an order can be resumed/paid for without a new order being + * created. + * + * @internal Core checkout uses order_awaiting_payment, Blocks checkout uses store_api_draft_order. Both validate the + * cart hash to ensure the order matches the cart. + * + * @param int $order_id The order ID that is awaiting payment, or 0 to unset it. + */ + protected function set_order_awaiting_payment( $order_id ) { + WC()->session->set( 'order_awaiting_payment', $order_id ); + WC()->session->set( 'store_api_draft_order', $order_id ); + + if ( $order_id ) { + $this->set_cart_hash( $order_id ); + } + } + /** * Set up cart item meta data to complete a subscription renewal via the cart. * @@ -251,8 +286,8 @@ class WCS_Cart_Renewal { foreach ( $subscription->get_items() as $item_id => $line_item ) { - $variations = array(); - $item_data = array(); + $variations = array(); + $item_data = array(); $custom_line_item_meta = array(); $reserved_item_meta_keys = array( '_item_meta', @@ -287,7 +322,7 @@ class WCS_Cart_Renewal { $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', $product_id ); $product = wc_get_product( $product_id ); - // The notice displayed when a subscription product has been deleted and the custoemr attempts to manually renew or make a renewal payment for a failed recurring payment for that product/subscription + // The notice displayed when a subscription product has been deleted and the customer attempts to manually renew or make a renewal payment for a failed recurring payment for that product/subscription // translators: placeholder is an item name $product_deleted_error_message = apply_filters( 'woocommerce_subscriptions_renew_deleted_product_error_message', __( 'The %s product has been deleted and can no longer be renewed. Please choose a new product or contact us for assistance.', 'woocommerce-subscriptions' ) ); @@ -296,7 +331,7 @@ class WCS_Cart_Renewal { wc_add_notice( sprintf( $product_deleted_error_message, $item_name ), 'error' ); - // Make sure we don't actually need the variation ID (if the product was a variation, it will have a variation ID; however, if the product has changed from a simple subscription to a variable subscription, there will be no variation_id) + // Make sure we don't actually need the variation ID (if the product was a variation, it will have a variation ID; however, if the product has changed from a simple subscription to a variable subscription, there will be no variation_id) } elseif ( $product->is_type( array( 'variable-subscription' ) ) && ! empty( $variation_id ) ) { $variation = wc_get_product( $variation_id ); @@ -358,7 +393,7 @@ class WCS_Cart_Renewal { continue; } - if ( isset( $item[ $this->cart_item_key ]['renewal_order_id'] ) && ! 'shop_order' == get_post_type( $item[ $this->cart_item_key ]['renewal_order_id'] ) ) { + if ( isset( $item[ $this->cart_item_key ]['renewal_order_id'] ) && ! 'shop_order' === WC_Data_Store::load( 'order' )->get_order_type( $item[ $this->cart_item_key ]['renewal_order_id'] ) ) { $cart->remove_cart_item( $key ); $removed_count_order++; continue; @@ -387,7 +422,7 @@ class WCS_Cart_Renewal { */ public function get_cart_item_from_session( $cart_item_session_data, $cart_item, $key ) { - if ( isset( $cart_item[ $this->cart_item_key ]['subscription_id'] ) ) { + if ( $this->should_honor_subscription_prices( $cart_item ) ) { $cart_item_session_data[ $this->cart_item_key ] = $cart_item[ $this->cart_item_key ]; $_product = $cart_item_session_data['data']; @@ -402,10 +437,26 @@ class WCS_Cart_Renewal { $price = $item_to_renew['line_subtotal']; if ( $_product->is_taxable() && $subscription->get_prices_include_tax() ) { - $price += array_sum( $item_to_renew['taxes']['subtotal'] ); // Use the taxes array items here as they contain taxes to a more accurate number of decimals. + + // If this item's subtracted tax data hasn't been repaired, do that now. + if ( isset( $item_to_renew['_subtracted_base_location_tax'] ) ) { + WC_Subscriptions_Upgrader::repair_subtracted_base_taxes( $item_to_renew->get_id() ); + + // The item has been updated so get a refreshed version of the item. + $item_to_renew = WC_Order_Factory::get_order_item( $item_to_renew->get_id() ); + } + + if ( isset( $item_to_renew['_subtracted_base_location_taxes'] ) ) { + $price += array_sum( $item_to_renew['_subtracted_base_location_taxes'] ) * $item_to_renew['qty']; + } else { + $price += array_sum( $item_to_renew['taxes']['subtotal'] ); // Use the taxes array items here as they contain taxes to a more accurate number of decimals. + } } - $_product->set_price( $price / $item_to_renew['qty'] ); + // In rare cases quantity can be zero. Check first to prevent triggering a fatal error in php8+ + if ( 0 !== (int) $item_to_renew['qty'] ) { + $_product->set_price( $price / $item_to_renew['qty'] ); + } // Don't carry over any sign up fee wcs_set_objects_property( $_product, 'subscription_sign_up_fee', 0, 'set_prop_only' ); @@ -510,7 +561,7 @@ class WCS_Cart_Renewal { $billing_address = array(); if ( $checkout_object->checkout_fields['billing'] ) { foreach ( array_keys( $checkout_object->checkout_fields['billing'] ) as $field ) { - $field_name = str_replace( 'billing_', '', $field ); + $field_name = str_replace( 'billing_', '', $field ); $billing_address[ $field_name ] = $checkout_object->get_posted_address_data( $field_name ); } } @@ -518,7 +569,7 @@ class WCS_Cart_Renewal { $shipping_address = array(); if ( $checkout_object->checkout_fields['shipping'] ) { foreach ( array_keys( $checkout_object->checkout_fields['shipping'] ) as $field ) { - $field_name = str_replace( 'shipping_', '', $field ); + $field_name = str_replace( 'shipping_', '', $field ); $shipping_address[ $field_name ] = $checkout_object->get_posted_address_data( $field_name, 'shipping' ); } } @@ -633,8 +684,8 @@ class WCS_Cart_Renewal { } } - //remove the renewal order flag - unset( WC()->session->order_awaiting_payment ); + // remove the renewal order flag + $this->set_order_awaiting_payment( 0 ); //clear renewal coupons $this->clear_coupons(); @@ -695,9 +746,9 @@ class WCS_Cart_Renewal { } } - //restore the renewal order flag + // restore the renewal order flag if ( isset( WC()->cart->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['renewal_order_id'] ) ) { - WC()->session->set( 'order_awaiting_payment', WC()->cart->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['renewal_order_id'] ); + $this->set_order_awaiting_payment( WC()->cart->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['renewal_order_id'] ); } } } @@ -728,7 +779,7 @@ class WCS_Cart_Renewal { // Tweak the coupon data for renewal coupons if ( $coupon_code == $code ) { - $expiry_date_property = WC_Subscriptions::is_woocommerce_pre( '3.0' ) ? 'expiry_date' : 'date_expires'; + $expiry_date_property = wcs_is_woocommerce_pre( '3.0' ) ? 'expiry_date' : 'date_expires'; // Some coupon properties are overridden specifically for renewals $renewal_coupon_overrides = array( @@ -780,7 +831,7 @@ class WCS_Cart_Renewal { protected function store_coupon( $order_id, $coupon ) { if ( ! empty( $order_id ) && ! empty( $coupon ) ) { $renewal_coupons = WC()->session->get( 'wcs_renewal_coupons', array() ); - $use_bools = WC_Subscriptions::is_woocommerce_pre( '3.0' ); // Some coupon properties have changed from accepting 'no' and 'yes' to true and false args. + $use_bools = wcs_is_woocommerce_pre( '3.0' ); // Some coupon properties have changed from accepting 'no' and 'yes' to true and false args. $coupon_properties = array(); $property_defaults = array( 'discount_type' => '', @@ -1004,6 +1055,7 @@ class WCS_Cart_Renewal { if ( $this->cart_contains() ) { // Update the cart stored in the session with the new data WC()->session->cart = WC()->cart->get_cart_for_session(); + WC()->cart->persistent_cart_update(); } } @@ -1047,11 +1099,11 @@ class WCS_Cart_Renewal { * After order meta is saved, get the order line item ID for this renewal and keep a record of it in * the cart so we can update it later. * - * @param int $order_id + * @param int|WC_Order $order_id * @param array $checkout_posted_data * @since 2.2.1 */ - public function set_order_item_id( $order_id, $posted_checkout_data ) { + public function set_order_item_id( $order_id, $posted_checkout_data = array() ) { $order = wc_get_order( $order_id ); @@ -1109,25 +1161,50 @@ class WCS_Cart_Renewal { if ( false !== $cart_renewal_item ) { $subscription = wcs_get_subscription( $cart_renewal_item[ $this->cart_item_key ]['subscription_id'] ); $billing_address = $shipping_address = array(); - foreach ( array( 'billing', 'shipping' ) as $address_type ) { $checkout_fields = WC()->checkout()->get_checkout_fields( $address_type ); if ( is_array( $checkout_fields ) ) { foreach ( array_keys( $checkout_fields ) as $field ) { if ( isset( $checkout_data[ $field ] ) ) { - $field_name = str_replace( $address_type . '_', '', $field ); + $field_name = str_replace( $address_type . '_', '', $field ); ${$address_type . '_address'}[ $field_name ] = $checkout_data[ $field ]; } } } } - $subscription->set_address( $billing_address, 'billing' ); $subscription->set_address( $shipping_address, 'shipping' ); } } + /** + * When completing checkout for a subscription renewal, update the subscription's address to match + * the shipping/billing address entered on checkout. + * + * @param \WC_Customer $customer + * @param \WP_REST_Request $request Full details about the request. + * @since 4.1.1 + */ + public function maybe_update_subscription_address_data_from_store_api( $customer, $request ) { + $cart_renewal_item = $this->cart_contains(); + + if ( false !== $cart_renewal_item ) { + $subscription = wcs_get_subscription( $cart_renewal_item[ $this->cart_item_key ]['subscription_id'] ); + + // Billing address is a required field. + foreach ( $request['billing_address'] as $key => $value ) { + if ( is_callable( [ $customer, "set_billing_$key" ] ) ) { + $customer->{"set_billing_$key"}( $value ); + } + } + // Billing address is a required field. + $subscription->set_address( $request['billing_address'], 'billing' ); + // If shipping address (optional field) was not provided, set it to the given billing address (required field). + $subscription->set_address( $request['shipping_address'] ?? $request['billing_address'], 'shipping' ); + } + } + /** * Add custom line item meta to the cart item data so it's displayed in the cart. * @@ -1303,14 +1380,14 @@ class WCS_Cart_Renewal { /** * Create coupon objects from coupon line items. * - * @param array $coupon_line_items The coupon line items to apply to the cart. + * @param WC_Order_Item_Coupon[] $coupon_line_items The coupon line items to apply to the cart. * @return array $coupons */ protected function get_line_item_coupons( $coupon_line_items ) { $coupons = array(); foreach ( $coupon_line_items as $coupon_item ) { - $coupon = new WC_Coupon( $coupon_item['name'] ); + $coupon = new WC_Coupon( $coupon_item->get_name() ); // If the coupon no longer exists, get a pseudo coupon for the discounting amount. if ( ! $coupon->get_id() > 0 ) { @@ -1320,7 +1397,7 @@ class WCS_Cart_Renewal { } $coupon = $this->get_pseudo_coupon( $coupon_item->get_discount() ); - $coupon->set_code( $coupon_item['code'] ); + $coupon->set_code( $coupon_item->get_code() ); } elseif ( 'subscription_renewal' === $this->cart_item_key ) { $coupon_type = $coupon->get_discount_type(); @@ -1390,7 +1467,7 @@ class WCS_Cart_Renewal { * @since 2.5.4 */ public function maybe_preserve_order_created_via( $order ) { - $changes = $order->get_changes(); + $changes = $order->get_changes(); $current_data = $order->get_data(); if ( isset( $changes['created_via'], $current_data['created_via'] ) && 'subscription' === $current_data['created_via'] && 'checkout' === $changes['created_via'] && wcs_order_contains_renewal( $order ) ) { @@ -1398,6 +1475,19 @@ class WCS_Cart_Renewal { } } + + /** + * Deteremines if the cart should honor the granfathered subscription/order line item total. + * + * @since 3.0.10 + * + * @param array $cart_item The cart item to check. + * @return bool Whether the cart should honor the order's prices. + */ + public function should_honor_subscription_prices( $cart_item ) { + return isset( $cart_item[ $this->cart_item_key ]['subscription_id'] ); + } + /** * Disables renewal cart stock validation if the store has switched it off via a filter. * @@ -1409,6 +1499,80 @@ class WCS_Cart_Renewal { } } + /** + * Overrides the place order button text on the checkout when the cart contains renewal order items, exclusively. + * + * @since 3.1.0 + * + * @param string $place_order_text The place order button text. + * @return string The place order button text. 'Renew subscription' if the cart contains only renewals, otherwise the default. + */ + public function order_button_text( $place_order_text ) { + if ( isset( WC()->cart ) && count( wcs_get_order_type_cart_items( 'renewal' ) ) === count( WC()->cart->get_cart() ) ) { + $place_order_text = _x( 'Renew subscription', 'The place order button text while renewing a subscription', 'woocommerce-subscriptions' ); + } + + return $place_order_text; + } + + /** + * Verifies if the cart being loaded from the session belongs to the current user. + * + * If a customer is logged out via the session cookie expiring or being killed, it's possible that + * their cart session persists. Before WC load it, we need to verify if it contains a + * subscription-related order and if so, whether the current user has permission to pay for it. + * + * This function will destroy any session which contains a subscription-related payment that doesn't belong to the current user. + * + * @since 1.6.3 + */ + public function verify_session_belongs_to_customer() { + $cart = WC()->session->get( 'cart', null ); + $customer = WC()->session->get( 'customer', null ); + + if ( ! $cart ) { + return; + } + + foreach ( $cart as $cart_item ) { + $order = $this->get_order( $cart_item ); + + // If this cart item doesn't contain a subscription-related order, skip. + if ( ! $order ) { + continue; + } + + // If there is no logged in user. The session has most likely expired. + if ( ! is_user_logged_in() ) { + WC()->session->destroy_session(); + return; + } + + // If the session has a stored customer and that customer is no longer logged in, destroy the session. + if ( $customer && get_current_user_id() !== (int) $customer['id'] ) { + WC()->session->destroy_session(); + return; + } + + if ( ! $this->validate_current_user( $order ) ) { + WC()->session->destroy_session(); + return; + } + } + } + + /** + * Checks if the current user can pay for the order. + * + * @since 1.6.3 + * + * @param WC_Order $order The order to check the current user against. + * @return bool Whether the current user can pay for this order. + */ + public function validate_current_user( $order ) { + return current_user_can( 'pay_for_order', $order->get_id() ); + } + /* Deprecated */ /** @@ -1449,7 +1613,7 @@ class WCS_Cart_Renewal { */ public function update_line_item_cart_data( $item_id, $cart_item_data, $cart_item_key ) { - if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( false === wcs_is_woocommerce_pre( '3.0' ) ) { _deprecated_function( __METHOD__, '2.2.0 and WooCommerce 3.0', __CLASS__ . '::add_line_item_meta( $order_item, $cart_item_key, $cart_item )' ); } @@ -1516,7 +1680,7 @@ class WCS_Cart_Renewal { foreach ( $coupon_items as $coupon_item ) { - $coupon = new WC_Coupon( $coupon_item['name'] ); + $coupon = new WC_Coupon( $coupon_item->get_name() ); $coupon_type = wcs_get_coupon_property( $coupon, 'discount_type' ); $coupon_code = ''; @@ -1562,7 +1726,7 @@ class WCS_Cart_Renewal { } } } - // If there are no coupons but there is still a discount (i.e. it might have been manually added), we need to account for that as well + // If there are no coupons but there is still a discount (i.e. it might have been manually added), we need to account for that as well } elseif ( ! empty( $order_discount ) ) { $coupon = new WC_Coupon( 'discount_renewal' ); diff --git a/includes/class-wcs-cart-resubscribe.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php similarity index 87% rename from includes/class-wcs-cart-resubscribe.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php index f5f6c71..3e6b5ec 100644 --- a/includes/class-wcs-cart-resubscribe.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-resubscribe.php @@ -251,13 +251,15 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal { * @since 2.1 */ public function recurring_cart_next_payment_date( $first_renewal_date, $cart ) { - foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) { + foreach ( $cart->get_cart() as $cart_item ) { $subscription = $this->get_order( $cart_item ); - if ( false !== $subscription && $subscription->has_status( 'pending-cancel' ) ) { + + if ( $this->is_pre_cancelled_resubscribe( $subscription ) ) { $first_renewal_date = ( '1' != WC_Subscriptions_Product::get_length( $cart_item['data'] ) ) ? $subscription->get_date( 'end' ) : 0; break; } } + return $first_renewal_date; } @@ -271,7 +273,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal { public function maybe_set_free_trial( $total = '' ) { $subscription = $this->get_order(); - if ( false !== $subscription && $subscription->has_status( 'pending-cancel' ) ) { + if ( $this->is_pre_cancelled_resubscribe( $subscription ) ) { foreach ( WC()->cart->cart_contents as &$cart_item ) { if ( isset( $cart_item[ $this->cart_item_key ] ) ) { wcs_set_objects_property( $cart_item['data'], 'subscription_trial_length', 1, 'set_prop_only' ); @@ -292,7 +294,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal { public function maybe_unset_free_trial( $total = '' ) { $subscription = $this->get_order(); - if ( false !== $subscription && $subscription->has_status( 'pending-cancel' ) ) { + if ( $this->is_pre_cancelled_resubscribe( $subscription ) ) { foreach ( WC()->cart->cart_contents as &$cart_item ) { if ( isset( $cart_item[ $this->cart_item_key ] ) ) { wcs_set_objects_property( $cart_item['data'], 'subscription_trial_length', 0, 'set_prop_only' ); @@ -310,9 +312,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal { */ public function maybe_cancel_existing_subscription( $order_id, $old_order_status, $new_order_status ) { if ( wcs_order_contains_subscription( $order_id ) && wcs_order_contains_resubscribe( $order_id ) ) { - $order = wc_get_order( $order_id ); - $order_completed = in_array( $new_order_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ); - $order_needed_payment = in_array( $old_order_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); + $order = wc_get_order( $order_id ); foreach ( wcs_get_subscriptions_for_resubscribe_order( $order_id ) as $subscription ) { if ( $subscription->has_status( 'pending-cancel' ) ) { @@ -323,4 +323,45 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal { } } } + + /** + * Overrides the place order button text on the checkout when the cart contains only resubscribe requests. + * + * @since 3.1.0 + * + * @param string $place_order_text The place order button text. + * @return string The place order button text. 'Resubscribe' if the cart contains only resubscribe requests, otherwise the default. + */ + public function order_button_text( $place_order_text ) { + + if ( isset( WC()->cart ) && count( wcs_get_order_type_cart_items( 'resubscribe' ) ) === count( WC()->cart->get_cart() ) ) { + $place_order_text = _x( 'Resubscribe', 'The place order button text while resubscribing to a subscription', 'woocommerce-subscriptions' ); + } + + return $place_order_text; + } + + /** + * Determines if the customer is resubscribe prior to the subscription being cancelled. + * + * @since 3.1.0 + * + * @param WC_Subscription $subscription + * @return bool + */ + private function is_pre_cancelled_resubscribe( $subscription ) { + return is_a( $subscription, 'WC_Subscription' ) && $subscription->has_status( 'pending-cancel' ) && $subscription->get_time( 'end' ) > gmdate( 'U' ); + } + + /** + * Checks if the current user can resubscribe to the subscription. + * + * @since 1.6.3 + * + * @param WC_Subscription $subscription The WC subscription to validate the current user against. + * @return bool Whether the current user can resubscribe to the subscription. + */ + public function validate_current_user( $subscription ) { + return current_user_can( 'subscribe_again', $subscription->get_id() ); + } } diff --git a/includes/class-wcs-change-payment-method-admin.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php similarity index 91% rename from includes/class-wcs-change-payment-method-admin.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php index b9c0bfe..6f2c4c2 100644 --- a/includes/class-wcs-change-payment-method-admin.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php @@ -23,7 +23,8 @@ class WCS_Change_Payment_Method_Admin { $valid_payment_methods = self::get_valid_payment_methods( $subscription ); if ( ! $subscription->is_manual() && ! isset( $valid_payment_methods[ $payment_method ] ) ) { - $subscription_payment_gateway = WC_Subscriptions_Payment_Gateways::get_payment_gateway( $payment_method ); + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); + $subscription_payment_gateway = $payment_gateways_handler::get_payment_gateway( $payment_method ); if ( false != $subscription_payment_gateway ) { $valid_payment_methods[ $payment_method ] = $subscription_payment_gateway->title; @@ -140,9 +141,10 @@ class WCS_Change_Payment_Method_Admin { if ( ! $subscription->is_manual() && ( '' == $payment_gateway || $subscription->get_payment_method() != $payment_gateway->id ) ) { // Before updating to a new payment gateway make sure the subscription status is updated with the current gateway - $gateway_status = apply_filters( 'wcs_gateway_status_payment_changed', 'cancelled', $subscription, $payment_gateway ); + $gateway_status = apply_filters( 'wcs_gateway_status_payment_changed', 'cancelled', $subscription, $payment_gateway ); + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); - WC_Subscriptions_Payment_Gateways::trigger_gateway_status_updated_hook( $subscription, $gateway_status ); + $payment_gateways_handler::trigger_gateway_status_updated_hook( $subscription, $gateway_status ); } // Update the payment method for manual only if it has changed. @@ -171,9 +173,8 @@ class WCS_Change_Payment_Method_Admin { foreach ( $available_gateways as $gateway_id => $gateway ) { - if ( $gateway->supports( 'subscription_payment_method_change_admin' ) && 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) || ( ! $subscription->is_manual() && $gateway_id == $subscription->get_payment_method() ) ) { + if ( $gateway->supports( 'subscription_payment_method_change_admin' ) && ! wcs_is_manual_renewal_required() || ( ! $subscription->is_manual() && $gateway_id == $subscription->get_payment_method() ) ) { $valid_gateways[ $gateway_id ] = $gateway->get_title(); - } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wcs-core-autoloader.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-core-autoloader.php new file mode 100644 index 0000000..890283e --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-core-autoloader.php @@ -0,0 +1,254 @@ +base_path = untrailingslashit( $base_path ); + } + + /** + * Destructor. + */ + public function __destruct() { + $this->unregister(); + } + + /** + * Register the autoloader. + * + * @author Jeremy Pry + */ + public function register() { + spl_autoload_register( array( $this, 'autoload' ) ); + } + + /** + * Unregister the autoloader. + */ + public function unregister() { + spl_autoload_unregister( array( $this, 'autoload' ) ); + } + + /** + * Autoload a class. + * + * @author Jeremy Pry + * + * @param string $class The class name to autoload. + */ + public function autoload( $class ) { + $class = strtolower( $class ); + + if ( ! $this->should_autoload( $class ) ) { + return; + } + + $full_path = $this->get_class_base_path( $class ) . $this->get_relative_class_path( $class ) . $this->get_file_name( $class ); + + if ( is_readable( $full_path ) ) { + require_once( $full_path ); + } + } + + /** + * Gets the base path for a given class. + * + * @since 4.0.0 + * @return string + */ + public function get_class_base_path( $class ) { + return $this->base_path; + } + + /** + * Determine whether we should autoload a given class. + * + * @author Jeremy Pry + * + * @param string $class The class name. + * + * @return bool + */ + protected function should_autoload( $class ) { + // We're not using namespaces, so if the class has namespace separators, skip. + if ( false !== strpos( $class, '\\' ) ) { + return false; + } + + return false !== strpos( $class, 'wcs_' ) || 0 === strpos( $class, 'wc_subscription' ) || ( false !== strpos( $class, 'wc_' ) && false !== strpos( $class, 'subscription' ) ); + } + + /** + * Convert the class name into an appropriate file name. + * + * @author Jeremy Pry + * + * @param string $class The class name. + * + * @return string The file name. + */ + protected function get_file_name( $class ) { + $file_prefix = 'class-'; + + if ( $this->is_class_abstract( $class ) ) { + $file_prefix = 'abstract-'; + } elseif ( $this->is_class_interface( $class ) ) { + $file_prefix = 'interface-'; + } + + return $file_prefix . str_replace( '_', '-', $class ) . '.php'; + } + + /** + * Determine if the class is one of our abstract classes. + * + * @author Jeremy Pry + * + * @param string $class The class name. + * + * @return bool + */ + protected function is_class_abstract( $class ) { + static $abstracts = array( + 'wcs_background_repairer' => true, + 'wcs_background_updater' => true, + 'wcs_background_upgrader' => true, + 'wcs_cache_manager' => true, + 'wcs_debug_tool' => true, + 'wcs_debug_tool_cache_updater' => true, + 'wcs_dynamic_hook_deprecator' => true, + 'wcs_hook_deprecator' => true, + 'wcs_scheduler' => true, + 'wcs_sv_api_base' => true, + 'wcs_customer_store' => true, + 'wcs_related_order_store' => true, + 'wcs_migrator' => true, + 'wcs_table_maker' => true, + 'wcs_deprecated_functions_handler' => true, + ); + + return isset( $abstracts[ $class ] ); + } + + /** + * Determine if the class is one of our class interfaces. + * + * @param string $class The class name. + + * @return bool + */ + protected function is_class_interface( $class ) { + static $interfaces = array( + 'wcs_cache_updater' => true, + ); + + return isset( $interfaces[ $class ] ); + } + + /** + * Determine if the class is one of our data stores. + * + * @param string $class The class name. + + * @return bool + */ + protected function is_class_data_store( $class ) { + static $data_stores = array( + 'wcs_related_order_store_cached_cpt' => true, + 'wcs_related_order_store_cpt' => true, + 'wcs_customer_store_cached_cpt' => true, + 'wcs_customer_store_cpt' => true, + 'wcs_product_variable_data_store_cpt' => true, + 'wcs_subscription_data_store_cpt' => true, + ); + + return isset( $data_stores[ $class ] ); + } + + /** + * Get the relative path for the class location. + * + * This handles all of the special class locations and exceptions. + * + * @author Jeremy Pry + * + * @param string $class The class name. + * + * @return string The relative path (from the plugin root) to the class file. + */ + protected function get_relative_class_path( $class ) { + $path = '/includes'; + $is_admin = ( false !== strpos( $class, 'admin' ) ); + + if ( $this->is_class_abstract( $class ) ) { + if ( 'wcs_sv_api_base' === $class ) { + $path .= '/gateways/paypal/includes/abstracts'; + } else { + $path .= '/abstracts'; + } + } elseif ( $this->is_class_interface( $class ) ) { + $path .= '/interfaces'; + } elseif ( false !== strpos( $class, 'paypal' ) ) { + $path .= '/gateways/paypal'; + if ( 'wcs_paypal' === $class ) { + $path .= ''; + } elseif ( 'wcs_repair_suspended_paypal_subscriptions' === $class ) { + // Deliberately avoid concatenation for this class, using the base path. + $path = '/includes/upgrades'; + } elseif ( $is_admin ) { + $path .= '/includes/admin'; + } elseif ( 'wc_paypal_standard_subscriptions' === $class ) { + $path .= '/includes/deprecated'; + } else { + $path .= '/includes'; + } + } elseif ( $is_admin && 'wcs_change_payment_method_admin' !== $class ) { + $path .= '/admin'; + } elseif ( false !== strpos( $class, 'meta_box' ) ) { + $path .= '/admin/meta-boxes'; + } elseif ( false !== strpos( $class, 'debug_tool' ) ) { + $path .= '/admin/debug-tools'; + } elseif ( $this->is_class_data_store( $class ) ) { + $path .= '/data-stores'; + } elseif ( false !== strpos( $class, 'deprecat' ) ) { + $path .= '/deprecated'; + + if ( false !== strpos( $class, 'handler' ) ) { + $path .= '/deprecation-handlers'; + } + } elseif ( false !== strpos( $class, 'email' ) && 'wc_subscriptions_email' !== $class ) { + $path .= '/emails'; + } elseif ( false !== strpos( $class, 'gateway' ) && 'wc_subscriptions_change_payment_gateway' !== $class ) { + $path .= '/gateways'; + } elseif ( false !== strpos( $class, 'legacy' ) || 'wcs_array_property_post_meta_black_magic' === $class ) { + $path .= '/legacy'; + } elseif ( false !== strpos( $class, 'privacy' ) ) { + $path .= '/privacy'; + } elseif ( false !== strpos( $class, 'upgrade' ) || false !== strpos( $class, 'repair' ) ) { + $path .= '/upgrades'; + } + + return trailingslashit( $path ); + } +} diff --git a/includes/class-wcs-custom-order-item-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-custom-order-item-manager.php similarity index 100% rename from includes/class-wcs-custom-order-item-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-custom-order-item-manager.php diff --git a/includes/class-wcs-dependent-hook-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-dependent-hook-manager.php similarity index 100% rename from includes/class-wcs-dependent-hook-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-dependent-hook-manager.php diff --git a/includes/class-wcs-download-handler.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-download-handler.php similarity index 95% rename from includes/class-wcs-download-handler.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-download-handler.php index 42bff19..3f2469e 100644 --- a/includes/class-wcs-download-handler.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-download-handler.php @@ -23,9 +23,6 @@ class WCS_Download_Handler { * @since 2.0 */ public static function init() { - - add_filter( 'woocommerce_process_product_file_download_paths_grant_access_to_new_file', __CLASS__ . '::maybe_revoke_immediate_access', 10, 4 ); - add_action( 'woocommerce_grant_product_download_permissions', __CLASS__ . '::save_downloadable_product_permissions' ); add_filter( 'woocommerce_get_item_downloads', __CLASS__ . '::get_item_downloads', 10, 3 ); @@ -39,25 +36,6 @@ class WCS_Download_Handler { add_action( 'woocommerce_process_product_file_download_paths', __CLASS__ . '::grant_new_file_product_permissions', 11, 3 ); } - /** - * When adding new downloadable content to a subscription product, check if we don't - * want to automatically add the new downloadable files to the subscription or initial and renewal orders. - * - * @param bool $grant_access - * @param string $download_id - * @param int $product_id - * @param WC_Order $order - * @return bool - * @since 2.0 - */ - public static function maybe_revoke_immediate_access( $grant_access, $download_id, $product_id, $order ) { - - if ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_drip_downloadable_content_on_renewal', 'no' ) && ( wcs_is_subscription( wcs_get_objects_property( $order, 'id' ) ) || wcs_order_contains_subscription( $order, 'any' ) ) ) { - $grant_access = false; - } - return $grant_access; - } - /** * Save the download permissions on the individual subscriptions as well as the order. Hooked into * 'woocommerce_grant_product_download_permissions', which is strictly after the order received all the info @@ -244,7 +222,7 @@ class WCS_Download_Handler { foreach ( $subscriptions as $subscription_id ) { // Grant permissions to subscriptions which have no permissions for this product, pre WC3.0, or all subscriptions, post WC3.0, as WC doesn't grant them retrospectively anymore. - if ( ! in_array( $subscription_id, array_keys( $permissions_by_order_id ) ) || false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! in_array( $subscription_id, array_keys( $permissions_by_order_id ) ) || false === wcs_is_woocommerce_pre( '3.0' ) ) { $subscription = wcs_get_subscription( $subscription_id ); foreach ( $new_download_ids as $download_id ) { @@ -259,4 +237,27 @@ class WCS_Download_Handler { } } } + + /** + * When adding new downloadable content to a subscription product, check if we don't + * want to automatically add the new downloadable files to the subscription or initial and renewal orders. + * + * @deprecated 4.0.0 + * + * @param bool $grant_access + * @param string $download_id + * @param int $product_id + * @param WC_Order $order + * @return bool + * @since 2.0 + */ + public static function maybe_revoke_immediate_access( $grant_access, $download_id, $product_id, $order ) { + wcs_deprecated_function( __METHOD__, '4.0.0', 'WCS_Drip_Downloads_Manager::maybe_revoke_immediate_access() if available' ); + + if ( class_exists( 'WCS_Drip_Downloads_Manager' ) ) { + return WCS_Drip_Downloads_Manager::maybe_revoke_immediate_access( $grant_access, $download_id, $product_id, $order ); + } + + return $grant_access; + } } diff --git a/includes/class-wcs-failed-scheduled-action-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php similarity index 73% rename from includes/class-wcs-failed-scheduled-action-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php index dbefd51..963b9a0 100644 --- a/includes/class-wcs-failed-scheduled-action-manager.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php @@ -52,6 +52,8 @@ class WCS_Failed_Scheduled_Action_Manager { */ public function init() { add_action( 'action_scheduler_failed_action', array( $this, 'log_action_scheduler_failure' ), 10, 2 ); + add_action( 'action_scheduler_failed_execution', array( $this, 'log_action_scheduler_failure' ), 10, 2 ); + add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_action_scheduler_failure' ), 10, 2 ); add_action( 'admin_notices', array( $this, 'maybe_show_admin_notice' ) ); } @@ -68,11 +70,11 @@ class WCS_Failed_Scheduled_Action_Manager { /** * When a scheduled action failure is triggered, log information about the failed action to a WC logger. * - * @param int $action_id the action which failed. - * @param int $timeout the number of seconds an action can run for before timing out. + * @param int $action_id The ID of the action which failed. + * @param int|Exception|array $error The number of seconds an action timeouts out after or the exception/error that caused the error/shutdown. * @since 2.2.19 */ - public function log_action_scheduler_failure( $action_id, $timeout ) { + public function log_action_scheduler_failure( $action_id, $error ) { $action = $this->get_action( $action_id ); if ( ! isset( $this->tracked_scheduled_actions[ $action->get_hook() ] ) ) { @@ -81,7 +83,18 @@ class WCS_Failed_Scheduled_Action_Manager { $subscription_action = $this->get_action_hook_label( $action->get_hook() ); - $this->log( sprintf( 'scheduled action %s (%s) failed to finish processing after %s seconds', $action_id, $subscription_action, $timeout ) ); + switch ( current_filter() ) { + case 'action_scheduler_failed_action': + $this->log( sprintf( 'scheduled action %s (%s) failed to finish processing after %s seconds', $action_id, $subscription_action, absint( $error ) ) ); + break; + case 'action_scheduler_failed_execution': + $this->log( sprintf( 'scheduled action %s (%s) failed to finish processing due to the following exception: %s', $action_id, $subscription_action, $error->getMessage() ) ); + break; + case 'action_scheduler_unexpected_shutdown': + $this->log( sprintf( 'scheduled action %s (%s) failed to finish processing due to the following error: %s', $action_id, $subscription_action, $error['message'] ) ); + break; + } + $this->log( sprintf( 'action args: %s', $this->get_action_args_string( $action->get_args() ) ) ); // Store information about the scheduled action for displaying an admin notice @@ -101,6 +114,12 @@ class WCS_Failed_Scheduled_Action_Manager { * @since 2.2.19 */ public function maybe_show_admin_notice() { + + // Responding to this notice requires investigating subscriptions and scheduled actions so only display it to users who can manage woocommerce. + if ( ! current_user_can( 'manage_woocommerce' ) ) { + return; + } + $this->maybe_disable_admin_notice(); $failed_scheduled_actions = get_option( WC_Subscriptions_Admin::$option_prefix . '_failed_scheduled_actions', array() ); @@ -111,11 +130,16 @@ class WCS_Failed_Scheduled_Action_Manager { $affected_subscription_events = $separator = ''; foreach ( array_slice( $failed_scheduled_actions, -10, 10 ) as $action ) { + $id = false; - if ( isset( $action['args']['subscription_id'] ) ) { - $subject = '#' . $action['args']['subscription_id'] . ''; - } elseif ( isset( $action['args']['order_id'] ) ) { - $subject = '#' . $action['args']['order_id'] . ''; + if ( isset( $action['args']['subscription_id'] ) && wcs_is_subscription( $action['args']['subscription_id'] ) ) { + $id = $action['args']['subscription_id']; + } elseif ( isset( $action['args']['order_id'] ) && wc_get_order( $action['args']['order_id'] ) ) { + $id = $action['args']['order_id']; + } + + if ( $id ) { + $subject = '#' . $id . ''; } else { $subject = 'unknown'; } @@ -125,7 +149,7 @@ class WCS_Failed_Scheduled_Action_Manager { } $notice = new WCS_Admin_Notice( 'error' ); - $notice->set_content_template( 'html-failed-scheduled-action-notice.php', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/', array( + $notice->set_content_template( 'html-failed-scheduled-action-notice.php', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/' ), array( 'failed_scheduled_actions' => $failed_scheduled_actions, 'affected_subscription_events' => $affected_subscription_events, ) ); diff --git a/includes/class-wcs-initial-cart-stock-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-initial-cart-stock-manager.php similarity index 100% rename from includes/class-wcs-initial-cart-stock-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-initial-cart-stock-manager.php diff --git a/includes/class-wcs-limiter.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php similarity index 75% rename from includes/class-wcs-limiter.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php index d2593ee..7651700 100644 --- a/includes/class-wcs-limiter.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-limiter.php @@ -19,8 +19,8 @@ class WCS_Limiter { // Add limiting subscriptions options on edit product page add_action( 'woocommerce_product_options_advanced', __CLASS__ . '::admin_edit_product_fields' ); - // Only attach limited subscription purchasability logic on the front end. - if ( wcs_is_frontend_request() ) { + // Only attach limited subscription purchasability logic on the front end or during checkout block requests. + if ( wcs_is_frontend_request() || wcs_is_checkout_blocks_api_request() ) { add_filter( 'woocommerce_subscription_is_purchasable', __CLASS__ . '::is_purchasable_switch', 12, 2 ); add_filter( 'woocommerce_subscription_variation_is_purchasable', __CLASS__ . '::is_purchasable_switch', 12, 2 ); add_filter( 'woocommerce_subscription_is_purchasable', __CLASS__ . '::is_purchasable_renewal', 12, 2 ); @@ -107,11 +107,12 @@ class WCS_Limiter { */ public static function is_purchasable_product( $is_purchasable, $product ) { - //Set up cache + // Set up cache if ( ! isset( self::$is_purchasable_cache[ $product->get_id() ] ) ) { self::$is_purchasable_cache[ $product->get_id() ] = array(); } + // Populate the cache if it hasn't been set yet. if ( ! isset( self::$is_purchasable_cache[ $product->get_id() ]['standard'] ) ) { self::$is_purchasable_cache[ $product->get_id() ]['standard'] = $is_purchasable; @@ -122,8 +123,8 @@ class WCS_Limiter { } } } - return self::$is_purchasable_cache[ $product->get_id() ]['standard']; + return self::$is_purchasable_cache[ $product->get_id() ]['standard']; } /** @@ -146,6 +147,7 @@ class WCS_Limiter { return self::$is_purchasable_cache[ $product_key ]['switch']; } + // If the product is already purchasble, we don't need to determine it's purchasibility via switching/auto-switching. if ( true === $is_purchasable || ! is_user_logged_in() || ! wcs_is_product_switchable_type( $product ) || ! WC_Subscriptions_Product::is_subscription( $product->get_id() ) ) { self::$is_purchasable_cache[ $product_key ]['switch'] = $is_purchasable; return self::$is_purchasable_cache[ $product_key ]['switch']; @@ -159,15 +161,8 @@ class WCS_Limiter { return self::$is_purchasable_cache[ $product_key ]['switch']; } - // Limited products are only purchasable while switching the subscription which contains that product so we need the customer's subscriptions to this product. - $subscriptions = wcs_get_subscriptions( array( - 'customer_id' => $user_id, - 'status' => $product_limitation, - 'product_id' => $product->get_id(), - ) ); - // Adding to cart - if ( isset( $_GET['switch-subscription'] ) && array_key_exists( $_GET['switch-subscription'], $subscriptions ) ) { + if ( isset( $_GET['switch-subscription'] ) && array_key_exists( $_GET['switch-subscription'], self::get_user_subscriptions_to_product( $product, $user_id, $product_limitation ) ) ) { $is_purchasable = true; } else { // If we have a variation product get the variable product's ID. We can't use the variation ID for comparison because this function sometimes receives a variable product. @@ -175,7 +170,7 @@ class WCS_Limiter { $cart_contents = array(); // Use the version of the cart we have access to. We may need to look for switches in the cart being loaded from the session. - if ( WC_Subscriptions_Switcher::cart_contains_switches() ) { + if ( wcs_cart_contains_switches() ) { $cart_contents = WC()->cart->cart_contents; } elseif ( isset( WC()->session->cart ) ) { $cart_contents = WC()->session->cart; @@ -183,7 +178,7 @@ class WCS_Limiter { // Check if the cart contains a switch for this specific product. foreach ( $cart_contents as $cart_item ) { - if ( $product_id === $cart_item['product_id'] && isset( $cart_item['subscription_switch']['subscription_id'] ) && array_key_exists( $cart_item['subscription_switch']['subscription_id'], $subscriptions ) ) { + if ( $product_id === $cart_item['product_id'] && isset( $cart_item['subscription_switch']['subscription_id'] ) && array_key_exists( $cart_item['subscription_switch']['subscription_id'], self::get_user_subscriptions_to_product( $product, $user_id, $product_limitation ) ) ) { $is_purchasable = true; break; } @@ -232,38 +227,45 @@ class WCS_Limiter { /** * Check if the current session has an order awaiting payment for a subscription to a specific product line item. * - * @since 2.1 Moved from WC_Subscriptions_Product + * @since 2.1.0 + * @param int $product_id The product to look for a subscription awaiting payment. * @return bool **/ protected static function order_awaiting_payment_for_product( $product_id ) { global $wp; - if ( ! isset( self::$order_awaiting_payment_for_product[ $product_id ] ) ) { + if ( isset( self::$order_awaiting_payment_for_product[ $product_id ] ) ) { + return self::$order_awaiting_payment_for_product[ $product_id ]; + } - self::$order_awaiting_payment_for_product[ $product_id ] = false; + // Set up the cache with a default value. + self::$order_awaiting_payment_for_product[ $product_id ] = false; - if ( ! empty( WC()->session->order_awaiting_payment ) || isset( $_GET['pay_for_order'] ) ) { + // If there's no order waiting payment, exit early. + if ( empty( WC()->session->order_awaiting_payment ) && ! isset( $_GET['pay_for_order'] ) ) { + return self::$order_awaiting_payment_for_product[ $product_id ]; + } - $order_id = ! empty( WC()->session->order_awaiting_payment ) ? WC()->session->order_awaiting_payment : $wp->query_vars['order-pay']; - $order = wc_get_order( absint( $order_id ) ); + $order_id = ! empty( WC()->session->order_awaiting_payment ) ? WC()->session->order_awaiting_payment : $wp->query_vars['order-pay']; + $order = wc_get_order( absint( $order_id ) ); - if ( is_object( $order ) && $order->has_status( array( 'pending', 'failed' ) ) ) { - foreach ( $order->get_items() as $item ) { - if ( $item['product_id'] == $product_id || $item['variation_id'] == $product_id ) { + if ( is_object( $order ) && $order->has_status( array( 'pending', 'failed' ) ) ) { + foreach ( $order->get_items() as $item ) { - $subscriptions = wcs_get_subscriptions( array( - 'order_id' => wcs_get_objects_property( $order, 'id' ), - 'product_id' => $product_id, - ) ); + // If this order contains the product we're interested in, continue finding a related subscription. + if ( $item['product_id'] == $product_id || $item['variation_id'] == $product_id ) { + $subscriptions = wcs_get_subscriptions( + array( + 'order_id' => $order->get_id(), + 'subscription_status' => array( 'active', 'pending', 'on-hold' ), + ) + ); - if ( ! empty( $subscriptions ) ) { - $subscription = array_pop( $subscriptions ); - - if ( $subscription->has_status( array( 'pending', 'on-hold' ) ) ) { - self::$order_awaiting_payment_for_product[ $product_id ] = true; - } - } - break; + foreach ( $subscriptions as $subscription ) { + // Check that the subscription has the product we're interested in. + if ( $subscription->has_product( $product_id ) && $subscription->needs_payment() ) { + self::$order_awaiting_payment_for_product[ $product_id ] = true; + break 2; // break out of the $subscriptions and order line item loops - we've found at least 1 subscription pending payment for the product. } } } @@ -314,4 +316,39 @@ class WCS_Limiter { return array(); } } + + /** + * Gets a list of the customer subscriptions to a product with a particular limited status. + * + * @param WC_Product|int $product The product object or product ID. + * @param int $user_id The user's ID. + * @param string $limit_status The limit status. + * + * @return WC_Subscription[] An array of a customer's subscriptions with a specific status and product. + */ + protected static function get_user_subscriptions_to_product( $product, $user_id, $limit_status ) { + static $user_subscriptions_to_product = array(); + $product_id = is_object( $product ) ? $product->get_id() : $product; + $cache_key = "{$product_id}_{$user_id}_{$limit_status}"; + + if ( ! isset( $user_subscriptions_to_product[ $cache_key ] ) ) { + // Getting all the customers subscriptions and removing ones without the product is more performant than querying for subscriptions with the product. + $subscriptions = wcs_get_subscriptions( + array( + 'customer_id' => $user_id, + 'status' => $limit_status, + ) + ); + + foreach ( $subscriptions as $subscription_id => $subscription ) { + if ( ! $subscription->has_product( $product_id ) ) { + unset( $subscriptions[ $subscription_id ] ); + } + } + + $user_subscriptions_to_product[ $cache_key ] = $subscriptions; + } + + return $user_subscriptions_to_product[ $cache_key ]; + } } diff --git a/includes/class-wcs-modal.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-modal.php similarity index 90% rename from includes/class-wcs-modal.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-modal.php index a356df9..a329b5d 100644 --- a/includes/class-wcs-modal.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-modal.php @@ -83,8 +83,8 @@ class WCS_Modal { * @since 2.6.0 */ public static function enqueue_scripts_and_styles() { - wp_enqueue_script( 'wcs-modal-scripts', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/modal.js', array( 'jquery' ), WC_Subscriptions::$version, true ); - wp_enqueue_style( 'wcs-modal-styles', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/css/modal.css', array( 'dashicons' ), WC_Subscriptions::$version ); + wp_enqueue_script( 'wcs-modal-scripts', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/modal.js' ), array( 'jquery' ), WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(), true ); + wp_enqueue_style( 'wcs-modal-styles', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/css/modal.css' ), array( 'dashicons' ), WC_Subscriptions_Core_Plugin::instance()->get_plugin_version() ); } /** @@ -124,7 +124,7 @@ class WCS_Modal { * @since 2.6.0 */ public function print_html() { - wc_get_template( 'html-modal.php', array( 'modal' => $this ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); + wc_get_template( 'html-modal.php', array( 'modal' => $this ), '', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } /** @@ -144,7 +144,7 @@ class WCS_Modal { wc_get_template( $this->content['template_name'], $this->content['args'], '', $this->content['template_path'] ); break; case 'callback': - call_user_func_array( $this->content['callback'], $this->content['parameters'] ); + call_user_func_array( $this->content['callback'], array_values( $this->content['parameters'] ) ); break; } } diff --git a/includes/class-wcs-my-account-auto-renew-toggle.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php similarity index 100% rename from includes/class-wcs-my-account-auto-renew-toggle.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php diff --git a/includes/class-wcs-my-account-payment-methods.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php similarity index 70% rename from includes/class-wcs-my-account-payment-methods.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php index 9656cc1..6b20c7e 100644 --- a/includes/class-wcs-my-account-payment-methods.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-payment-methods.php @@ -25,6 +25,8 @@ class WCS_My_Account_Payment_Methods { add_action( 'woocommerce_payment_token_set_default', array( __CLASS__, 'display_default_payment_token_change_notice' ), 10, 2 ); add_action( 'wp', array( __CLASS__, 'update_subscription_tokens' ) ); + add_action( 'woocommerce_before_account_payment_methods', array( __CLASS__, 'print_deleting_notices' ) ); + add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_frontend_scripts' ) ); } /** @@ -48,8 +50,36 @@ class WCS_My_Account_Payment_Methods { $payment_token_data['actions']['delete']['url'] = add_query_arg( $delete_subscription_token_args, $payment_token_data['actions']['delete']['url'] ); } else { - // Cannot delete a token used for active subscriptions where there is no alternative - unset( $payment_token_data['actions']['delete'] ); + /** + * Allow third-party gateways to override whether the token delete button should be removed. + * + * Some gateways, like Bambora, don't allow customers to add a new card with the same card number but different expiry or cvv. + * This means customers updating their expiring card need to delete the exisitng card first before adding the new one. This + * isn't possible however because we prevent deleting tokens linked to active subscriptions. + * + * Gateways can use this filter to make their own checks to allow deletion. + * + * @since 3.1.0 + * + * @param bool Whether the delete button should be shown for tokens linked to a subscription. true - show, false - not shown (default). + * @param WC_Payment_Token The payment token in question. + */ + if ( isset( $payment_token_data['actions']['delete'] ) && ! apply_filters( 'wc_subscriptions_allow_subscription_token_deletion', false, $payment_token ) ) { + // Cannot delete a token used for active subscriptions where there is no alternative. + // Override the delete URL. We'll display a notice explaining why you cant delete that method instead. + $payment_token_data['actions']['wcs_deletion_error'] = $payment_token_data['actions']['delete']; + unset( $payment_token_data['actions']['delete'] ); + + // Determine which notice we need to display. The 'choose a default' or 'add a payment method'. + // If they have more than 1 alternative method, they need to select a default, otherwise they need to add one. + if ( count( WCS_Payment_Tokens::get_customer_tokens( $payment_token->get_user_id(), $payment_token->get_gateway_id() ) ) > 2 ) { + $notice_to_display = 'choose_default'; + } else { + $notice_to_display = 'add_method'; + } + + $payment_token_data['actions']['wcs_deletion_error']['url'] = "#{$notice_to_display}"; + } } } } @@ -205,6 +235,51 @@ class WCS_My_Account_Payment_Methods { exit(); } + /** + * Enqueues the frontend scripts for the My account > Payment methods page. + * + * @since 3.1.0 + */ + public static function enqueue_frontend_scripts() { + if ( 'payment-methods' !== WC()->query->get_current_endpoint() ) { + return; + } + + $script_params = array( + 'add_method_error' => sprintf( + // translators: %1$s opening strong HTML tag, %2$s closing strong HTML tag. + __( 'That payment method cannot be deleted because it is linked to an automatic subscription. Please %1$sadd a payment method%2$s, before trying again.', 'woocommerce-subscriptions' ), + '', + '' + ), + 'choose_default_error' => sprintf( + // translators: %1$s opening strong and em HTML tags, %2$s closing em HTML tag, %3$s closing strong HTML tag. + __( 'That payment method cannot be deleted because it is linked to an automatic subscription. Please choose a %1$sdefault%2$s payment method%3$s, before trying again.', 'woocommerce-subscriptions' ), + '', + '', + '' + ), + ); + + wp_enqueue_script( 'wc-subscriptions-payment-methods', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/frontend/payment-methods.js' ), array( 'jquery' ), WC_Subscriptions_Core_Plugin::instance()->get_plugin_version(), true ); + wp_localize_script( 'wc-subscriptions-payment-methods', 'wcs_payment_methods', $script_params ); + } + + /** + * Prints an error notice stub, to be used when a customer attempts to delete a payment token used by a subscription. + * + * @see self::enqueue_frontend_scripts() For the error message content. + * @see self::flag_subscription_payment_token_deletions() For the determination of when a token cannot be deleted. + * + * @since 3.1.0 + */ + public static function print_deleting_notices() { + // The notice is hidden on load, and only shown when a token delete request is made. + echo ''; + } + /** * Get subscriptions by a WC_Payment_Token. All automatic subscriptions with the token's payment method, * customer id and token value stored in post meta will be returned. diff --git a/includes/class-wcs-object-sorter.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-object-sorter.php similarity index 100% rename from includes/class-wcs-object-sorter.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-object-sorter.php diff --git a/includes/class-wcs-payment-tokens.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-payment-tokens.php similarity index 86% rename from includes/class-wcs-payment-tokens.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-payment-tokens.php index e799d66..85338dd 100644 --- a/includes/class-wcs-payment-tokens.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-payment-tokens.php @@ -34,7 +34,7 @@ class WCS_Payment_Tokens extends WC_Payment_Tokens { // Attempt to find the token meta key from the subscription payment meta and the old token. if ( is_array( $payment_meta_table ) ) { - foreach ( $payment_meta_table as $meta_table => $meta ) { + foreach ( $payment_meta_table as $meta ) { foreach ( $meta as $meta_key => $meta_data ) { if ( $old_token->get_token() === $meta_data['value'] ) { $token_meta_key = $meta_key; @@ -44,7 +44,26 @@ class WCS_Payment_Tokens extends WC_Payment_Tokens { } } - $updated = update_post_meta( $subscription->get_id(), $token_meta_key, $new_token->get_token(), $old_token->get_token() ); + $subscription->update_meta_data( $token_meta_key, $new_token->get_token() ); + $subscription->save(); + + // Copy the new token to the last renewal order if it needs payment so the retry system will pick up the new method. + $last_renewal_order = $subscription->get_last_order( 'all', 'renewal' ); + + if ( $last_renewal_order && $last_renewal_order->needs_payment() ) { + wcs_copy_payment_method_to_order( $subscription, $last_renewal_order ); + $last_renewal_order->save(); + } + + /** + * Enable third-party plugins to run their own updates and filter whether the token was updated or not. + * + * @param bool Whether the token was updated. Default is true. + * @param WC_Subscription $subscription + * @param WC_Payment_Token $new_token + * @param WC_Payment_Token $old_token + */ + $updated = apply_filters( 'woocommerce_subscriptions_update_subscription_token', true, $subscription, $new_token, $old_token ); if ( $updated ) { do_action( 'woocommerce_subscription_token_changed', $subscription, $new_token, $old_token ); diff --git a/includes/class-wcs-permalink-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-permalink-manager.php similarity index 100% rename from includes/class-wcs-permalink-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-permalink-manager.php diff --git a/includes/class-wcs-post-meta-cache-manager-many-to-one.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-post-meta-cache-manager-many-to-one.php similarity index 100% rename from includes/class-wcs-post-meta-cache-manager-many-to-one.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-post-meta-cache-manager-many-to-one.php diff --git a/includes/class-wcs-post-meta-cache-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-post-meta-cache-manager.php similarity index 97% rename from includes/class-wcs-post-meta-cache-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-post-meta-cache-manager.php index abc46a1..494b4e9 100644 --- a/includes/class-wcs-post-meta-cache-manager.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-post-meta-cache-manager.php @@ -199,8 +199,12 @@ class WCS_Post_Meta_Cache_Manager { throw new InvalidArgumentException( sprintf( __( 'Invalid update type: %s. Post update types supported are "add" or "delete". Updates are done on post meta directly.', 'woocommerce-subscriptions' ), $update_type ) ); } + $object = ( 'shop_order' === $this->post_type ) ? wc_get_order( $post_id ) : get_post( $post_id ); + foreach ( $this->meta_keys as $meta_key => $value ) { - $meta_value = ( 'add' === $update_type ) ? get_post_meta( $post_id, $meta_key, true ) : ''; + $property = preg_replace( '/^_/', '', $meta_key ); + $meta_value = ( 'add' === $update_type ) ? wcs_get_objects_property( $object, $property ) : ''; + $this->maybe_trigger_update_cache_hook( $update_type, $post_id, $meta_key, $meta_value ); } } diff --git a/includes/class-wcs-query.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php similarity index 86% rename from includes/class-wcs-query.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php index 37e92cd..535a5f0 100644 --- a/includes/class-wcs-query.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-query.php @@ -16,7 +16,6 @@ class WCS_Query extends WC_Query { if ( ! is_admin() ) { add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 ); add_action( 'parse_request', array( $this, 'parse_request' ), 0 ); - add_filter( 'woocommerce_get_breadcrumb', array( $this, 'add_breadcrumb' ), 10 ); add_action( 'pre_get_posts', array( $this, 'maybe_redirect_payment_methods' ) ); add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 11 ); add_filter( 'woocommerce_get_query_vars', array( $this, 'add_wcs_query_vars' ) ); @@ -25,18 +24,21 @@ class WCS_Query extends WC_Query { add_filter( 'woocommerce_account_menu_items', array( $this, 'add_menu_items' ) ); // Since WC 3.3.0, add_wcs_query_vars() is enough for custom endpoints to work. - if ( WC_Subscriptions::is_woocommerce_pre( '3.3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.3.0' ) ) { add_filter( 'woocommerce_get_endpoint_url', array( $this, 'get_endpoint_url' ), 10, 4 ); } add_filter( 'woocommerce_get_endpoint_url', array( $this, 'maybe_redirect_to_only_subscription' ), 10, 2 ); add_action( 'woocommerce_account_subscriptions_endpoint', array( $this, 'endpoint_content' ) ); add_filter( 'woocommerce_account_menu_item_classes', array( $this, 'maybe_add_active_class' ), 10, 2 ); + + add_filter( 'woocommerce_endpoint_subscriptions_title', array( $this, 'change_my_account_endpoint_title' ), 10, 2 ); + add_filter( 'woocommerce_endpoint_view-subscription_title', array( $this, 'change_my_account_endpoint_title' ), 10, 2 ); } $this->init_query_vars(); - if ( WC_Subscriptions::is_woocommerce_pre( '3.4' ) ) { + if ( wcs_is_woocommerce_pre( '3.4' ) ) { add_filter( 'woocommerce_account_settings', array( $this, 'add_endpoint_account_settings' ) ); } else { add_filter( 'woocommerce_get_settings_advanced', array( $this, 'add_endpoint_account_settings' ) ); @@ -52,28 +54,12 @@ class WCS_Query extends WC_Query { $this->query_vars = array( 'view-subscription' => $this->get_view_subscription_endpoint(), ); - if ( ! WC_Subscriptions::is_woocommerce_pre( '2.6' ) ) { - $this->query_vars['subscriptions'] = get_option( 'woocommerce_myaccount_subscriptions_endpoint', 'subscriptions' ); + if ( ! wcs_is_woocommerce_pre( '2.6' ) ) { + $this->query_vars['subscriptions'] = get_option( 'woocommerce_myaccount_subscriptions_endpoint', 'subscriptions' ); $this->query_vars['subscription-payment-method'] = get_option( 'woocommerce_myaccount_subscription_payment_method_endpoint', 'subscription-payment-method' ); } } - /** - * Adds endpoint breadcrumb when viewing subscription - * - * @param array $crumbs already assembled breadcrumb data - * @return array $crumbs if we're on a view-subscription page, then augmented breadcrumb data - */ - public function add_breadcrumb( $crumbs ) { - - foreach ( $this->query_vars as $key => $query_var ) { - if ( $this->is_query( $query_var ) ) { - $crumbs[] = array( $this->get_endpoint_title( $key ) ); - } - } - return $crumbs; - } - /** * Changes page title on view subscription page * @@ -96,19 +82,23 @@ class WCS_Query extends WC_Query { } /** - * Set the subscription page title when viewing a subscription. + * Hooks onto `woocommerce_endpoint_{$endpoint}_title` to return the correct page title for subscription endpoints + * in My Account. * - * @since 2.0 - * @param $title + * @param string $title + * @param string $endpoint + * @return string + * + * @since 3.0.10 */ - public function get_endpoint_title( $endpoint ) { + public function change_my_account_endpoint_title( $title, $endpoint ) { global $wp; switch ( $endpoint ) { case 'view-subscription': $subscription = wcs_get_subscription( $wp->query_vars['view-subscription'] ); // translators: placeholder is a subscription ID. - $title = ( $subscription ) ? sprintf( _x( 'Subscription #%s', 'hash before order number', 'woocommerce-subscriptions' ), $subscription->get_order_number() ) : ''; + $title = ( $subscription ) ? sprintf( _x( 'Subscription #%s', 'hash before order number', 'woocommerce-subscriptions' ), $subscription->get_order_number() ) : ''; break; case 'subscriptions': if ( ! empty( $wp->query_vars['subscriptions'] ) ) { @@ -117,9 +107,7 @@ class WCS_Query extends WC_Query { } else { $title = __( 'Subscriptions', 'woocommerce-subscriptions' ); } - break; - default: - $title = ''; + break; } @@ -167,9 +155,9 @@ class WCS_Query extends WC_Query { if ( $this->query_vars['subscriptions'] === $endpoint && is_account_page() ) { $subscriptions = wcs_get_users_subscriptions(); - if ( is_array( $subscriptions ) && 1 == count( $subscriptions ) && apply_filters( 'wcs_my_account_redirect_to_single_subscription', true ) ) { + if ( is_array( $subscriptions ) && 1 === count( $subscriptions ) && apply_filters( 'wcs_my_account_redirect_to_single_subscription', true ) ) { $subscription = reset( $subscriptions ); - $url = $subscription->get_view_order_url(); + $url = $subscription->get_view_order_url(); } } @@ -183,9 +171,9 @@ class WCS_Query extends WC_Query { */ public function endpoint_content( $current_page = 1 ) { - $current_page = empty( $current_page ) ? 1 : absint( $current_page ); + $current_page = empty( $current_page ) ? 1 : absint( $current_page ); - wc_get_template( 'myaccount/subscriptions.php', array( 'current_page' => $current_page ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' ); + wc_get_template( 'myaccount/subscriptions.php', array( 'current_page' => $current_page ), '', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' ) ); } /** @@ -260,10 +248,10 @@ class WCS_Query extends WC_Query { 'change_payment_method' => $subscription->get_id(), '_wpnonce' => wp_create_nonce(), ); - $url = add_query_arg( $args, $subscription->get_checkout_payment_url() ); + $url = add_query_arg( $args, $subscription->get_checkout_payment_url() ); } - wp_redirect( $url ); + wp_redirect( $url ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect exit(); } @@ -376,4 +364,26 @@ class WCS_Query extends WC_Query { return $classes; } + + /** + * Adds endpoint breadcrumb when viewing subscription. + * + * Deprecated as we now use the `woocommerce_endpoint_{$endpoint}_title` hook which automatically integrates with + * breadcrumb generation. + * + * @param array $crumbs already assembled breadcrumb data + * @return array $crumbs if we're on a view-subscription page, then augmented breadcrumb data + * + * @deprecated 3.0.10 + */ + public function add_breadcrumb( $crumbs ) { + _deprecated_function( __METHOD__, '3.0.10' ); + + foreach ( $this->query_vars as $key => $query_var ) { + if ( $this->is_query( $query_var ) ) { + $crumbs[] = array( $this->get_endpoint_title( $key ) ); + } + } + return $crumbs; + } } diff --git a/includes/class-wcs-remove-item.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php similarity index 100% rename from includes/class-wcs-remove-item.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-remove-item.php diff --git a/includes/class-wcs-renewal-cart-stock-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-renewal-cart-stock-manager.php similarity index 100% rename from includes/class-wcs-renewal-cart-stock-manager.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-renewal-cart-stock-manager.php diff --git a/includes/class-wcs-select2.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-select2.php similarity index 94% rename from includes/class-wcs-select2.php rename to vendor/woocommerce/subscriptions-core/includes/class-wcs-select2.php index da74408..014b4d8 100644 --- a/includes/class-wcs-select2.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-select2.php @@ -51,7 +51,7 @@ class WCS_Select2 { * @since 2.2 */ protected function get_property_name( $property ) { - $data_properties = WC_Subscriptions::is_woocommerce_pre( '3.0' ) ? array( 'placeholder', 'selected', 'allow_clear' ) : array( 'placeholder', 'allow_clear' ); + $data_properties = wcs_is_woocommerce_pre( '3.0' ) ? array( 'placeholder', 'selected', 'allow_clear' ) : array( 'placeholder', 'allow_clear' ); return in_array( $property, $data_properties ) ? 'data-' . $property : $property; } @@ -106,7 +106,7 @@ class WCS_Select2 { public function get_html() { $html = "\n\n"; - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { if ( isset( $this->attributes['class'] ) && $this->attributes['class'] === 'wc-enhanced-select' ) { $html .= '', - esc_attr( $input_type ), esc_attr( $shipping_method_index ), esc_attr( sanitize_title( $shipping_method->id ) ), esc_attr( $shipping_method->id ), esc_attr( $checked ) ); + printf( + '', + esc_attr( $input_type ), + esc_attr( $shipping_method_index ), + esc_attr( sanitize_title( $shipping_method->id ) ), + esc_attr( $shipping_method->id ), + esc_attr( $checked ) + ); } /** @@ -210,7 +220,7 @@ function wcs_cart_totals_shipping_method_price_label( $method, $cart ) { $price_label = ''; if ( 0 < $method->cost ) { - $display_prices_include_tax = WC_Subscriptions::is_woocommerce_pre( '3.3' ) ? ( 'incl' === WC()->cart->tax_display_cart ) : WC()->cart->display_prices_including_tax(); + $display_prices_include_tax = wcs_is_woocommerce_pre( '3.3' ) ? ( 'incl' === WC()->cart->tax_display_cart ) : WC()->cart->display_prices_including_tax(); if ( ! $display_prices_include_tax ) { $price_label .= wcs_cart_price_string( $method->cost, $cart ); @@ -268,7 +278,7 @@ function wcs_cart_totals_coupon_html( $coupon, $cart ) { $coupon = new WC_Coupon( $coupon ); } - $value = array(); + $value = array(); if ( $amount = $cart->get_coupon_discount_amount( wcs_get_coupon_property( $coupon, 'code' ), $cart->display_cart_ex_tax ) ) { $discount_html = '-' . wc_price( $amount ); @@ -298,9 +308,9 @@ function wcs_cart_totals_coupon_html( $coupon, $cart ) { * @param WC_Cart The cart to display the total for. */ function wcs_cart_totals_order_total_html( $cart ) { - $order_total_html = '' . $cart->get_total() . ' '; - $tax_total_html = ''; - $display_prices_include_tax = WC_Subscriptions::is_woocommerce_pre( '3.3' ) ? ( 'incl' === $cart->tax_display_cart ) : $cart->display_prices_including_tax(); + $order_total_html = '' . $cart->get_total() . ' '; + $tax_total_html = ''; + $display_prices_include_tax = wcs_is_woocommerce_pre( '3.3' ) ? ( 'incl' === $cart->tax_display_cart ) : $cart->display_prices_including_tax(); // If prices are tax inclusive, show taxes here if ( wc_tax_enabled() && $display_prices_include_tax ) { @@ -335,14 +345,20 @@ function wcs_cart_totals_order_total_html( $cart ) { */ function wcs_cart_price_string( $recurring_amount, $cart ) { - return wcs_price_string( apply_filters( 'woocommerce_cart_subscription_string_details', array( - 'recurring_amount' => $recurring_amount, + return wcs_price_string( + apply_filters( + 'woocommerce_cart_subscription_string_details', + array( + 'recurring_amount' => $recurring_amount, - // Schedule details - 'subscription_interval' => wcs_cart_pluck( $cart, 'subscription_period_interval' ), - 'subscription_period' => wcs_cart_pluck( $cart, 'subscription_period', '' ), - 'subscription_length' => wcs_cart_pluck( $cart, 'subscription_length' ), - ), $cart ) ); + // Schedule details + 'subscription_interval' => wcs_cart_pluck( $cart, 'subscription_period_interval' ), + 'subscription_period' => wcs_cart_pluck( $cart, 'subscription_period', '' ), + 'subscription_length' => wcs_cart_pluck( $cart, 'subscription_length' ), + ), + $cart + ) + ); } /** @@ -386,7 +402,7 @@ function wcs_add_cart_first_renewal_payment_date( $order_total_html, $cart ) { if ( 0 !== $cart->next_payment_date ) { $first_renewal_date = date_i18n( wc_date_format(), wcs_date_to_time( get_date_from_gmt( $cart->next_payment_date ) ) ); // translators: placeholder is a date - $order_total_html .= '
    ' . sprintf( __( 'First renewal: %s', 'woocommerce-subscriptions' ), $first_renewal_date ) . '
    '; + $order_total_html .= '
    ' . sprintf( __( 'First renewal: %s', 'woocommerce-subscriptions' ), $first_renewal_date ) . '
    '; } return $order_total_html; @@ -401,9 +417,12 @@ add_filter( 'wcs_cart_totals_order_total_html', 'wcs_add_cart_first_renewal_paym */ function wcs_get_cart_item_name( $cart_item, $include = array() ) { - $include = wp_parse_args( $include, array( - 'attributes' => false, - ) ); + $include = wp_parse_args( + $include, + array( + 'attributes' => false, + ) + ); $cart_item_name = $cart_item['data']->get_title(); @@ -437,3 +456,34 @@ function wcs_allow_protected_products_to_renew() { function wcs_disallow_protected_product_add_to_cart_validation() { add_filter( 'woocommerce_add_to_cart_validation', 'wc_protected_product_add_to_cart', 10, 2 ); } + +/** + * Gets all the cart items linked to a given subscription order type. + * + * @since 3.1.0 + * + * @param string $order_type The order type to get cart items for. Can be 'parent', 'renewal', 'resubscribe', 'switch'. + * @return array[] An array of cart items which are linked to an order or subscription by the order type relationship. + */ +function wcs_get_order_type_cart_items( $order_type ) { + $cart_items = array(); + + if ( ! in_array( $order_type, array( 'parent', 'renewal', 'resubscribe', 'switch' ) ) ) { + wcs_doing_it_wrong( __METHOD__, 'The parameter must be a valid subscription order type "parent", "renewal", "resubscribe", "switch".', '3.1.0' ); + return $cart_items; + } + + if ( empty( WC()->cart->cart_contents ) ) { + return $cart_items; + } + + $order_type_cart_key = 'parent' === $order_type ? 'subscription_initial_payment' : "subscription_$order_type"; + + foreach ( WC()->cart->cart_contents as $cart_item_key => $cart_item ) { + if ( isset( $cart_item[ $order_type_cart_key ] ) ) { + $cart_items[ $cart_item_key ] = $cart_item; + } + } + + return $cart_items; +} diff --git a/includes/wcs-compatibility-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-compatibility-functions.php similarity index 86% rename from includes/wcs-compatibility-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-compatibility-functions.php index 782522a..bef6aac 100644 --- a/includes/wcs-compatibility-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-compatibility-functions.php @@ -18,27 +18,19 @@ if ( ! defined( 'ABSPATH' ) ) { /** * Display a tooltip in the WordPress administration area. * - * Uses wc_help_tip() when WooCommerce 2.5+ is active, otherwise it manually prints the HTML for a tooltip. + * @since 2.1.0 * - * @param string $tip The content to display in the tooltip. - * @since 2.1.0 - * @return string + * @param string $tip The content to display in the tooltip. + * @param bool $allow_html Allow sanitized HTML if true or escape. Optional. False by default. + * @param string $class The help tip's class attribute. Optional. Default is 'woocommerce-help-tip'. + * + * @return string The helptip HTML. */ -function wcs_help_tip( $tip, $allow_html = false ) { +function wcs_help_tip( $tip, $allow_html = false, $class = 'woocommerce-help-tip' ) { + $help_tip = wc_help_tip( $tip, $allow_html ); - if ( function_exists( 'wc_help_tip' ) ) { - - $help_tip = wc_help_tip( $tip, $allow_html ); - - } else { - - if ( $allow_html ) { - $tip = wc_sanitize_tooltip( $tip ); - } else { - $tip = esc_attr( $tip ); - } - - $help_tip = sprintf( '', $tip, esc_url( WC()->plugin_url() ) ); + if ( 'woocommerce-help-tip' !== $class ) { + $help_tip = str_replace( 'woocommerce-help-tip', esc_attr( $class ), $help_tip ); } return $help_tip; @@ -106,13 +98,15 @@ function wcs_get_objects_property( $object, $property, $single = 'single', $defa if ( is_callable( array( $object, $function_name ) ) ) { $value = $object->$function_name(); } else { - // If we don't have a method for this specific property, but we are using WC 3.0, it may be set as meta data on the object so check if we can use that. - if ( method_exists( $object, 'get_meta' ) && $object->meta_exists( $prefixed_key ) ) { - if ( 'single' === $single ) { - $value = $object->get_meta( $prefixed_key, true ); - } else { - // WC_Data::get_meta() returns an array of stdClass objects with id, key & value properties when meta is available. - $value = wp_list_pluck( $object->get_meta( $prefixed_key, false ), 'value' ); + // If we don't have a method for this specific property, but we are using WC 3.0, use $object->get_meta(). + if ( method_exists( $object, 'get_meta' ) ) { + if ( $object->meta_exists( $prefixed_key ) ) { + if ( 'single' === $single ) { + $value = $object->get_meta( $prefixed_key, true ); + } else { + // WC_Data::get_meta() returns an array of stdClass objects with id, key & value properties when meta is available. + $value = wp_list_pluck( $object->get_meta( $prefixed_key, false ), 'value' ); + } } } elseif ( 'single' === $single && isset( $object->$property ) ) { // WC < 3.0. $value = $object->$property; @@ -164,14 +158,12 @@ function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta '_sale_price_dates_to' => 'set_date_on_sale_to', ); - // If we have a 3.0 object with a predefined setter function, use it + // If we have an object with a predefined setter function, use it if ( isset( $meta_setters_map[ $prefixed_key ] ) && is_callable( array( $object, $meta_setters_map[ $prefixed_key ] ) ) ) { $function = $meta_setters_map[ $prefixed_key ]; $object->$function( $value ); - // If we have a 3.0 object, use the setter if available. - } elseif ( is_callable( array( $object, 'set' . $prefixed_key ) ) ) { - + } elseif ( is_callable( array( $object, 'set' . $prefixed_key ) ) ) { // If we have an object, use the setter if available // Prices include tax is stored as a boolean in props but saved in the database as a string yes/no, so we need to normalise it here to make sure if we have a string (which can be passed to it by things like wcs_copy_order_meta()) that it's converted to a boolean before being set if ( '_prices_include_tax' === $prefixed_key && ! is_bool( $value ) ) { $value = 'yes' === $value; @@ -184,48 +176,14 @@ function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta $function_name = 'set' . str_replace( '_order', '', $prefixed_key ); $object->$function_name( $value ); - // If there is no setter, treat as meta within the 3.0.x object. - } elseif ( is_callable( array( $object, 'update_meta_data' ) ) ) { + } else { // If there is no setter, treat as meta within the data object $meta_key = ( 'prefix_meta_key' === $prefix_meta_key ) ? $prefixed_key : $key; $object->update_meta_data( $meta_key, $value, $meta_id ); - - // 2.6.x handling for name which is not meta. - } elseif ( 'name' === $key ) { - $object->post->post_title = $value; - - // 2.6.x handling for everything else. - } else { - $object->$key = $value; } // Save the data if ( 'save' === $save ) { - if ( is_callable( array( $object, 'save' ) ) ) { // WC 3.0+ - $object->save(); - } elseif ( 'date_created' == $key ) { // WC < 3.0+ - wp_update_post( - array( - 'ID' => wcs_get_objects_property( $object, 'id' ), - 'post_date' => get_date_from_gmt( $value ), - 'post_date_gmt' => $value, - ) - ); - } elseif ( 'name' === $key ) { // the replacement for post_title added in 3.0, need to update post_title not post meta - wp_update_post( - array( - 'ID' => wcs_get_objects_property( $object, 'id' ), - 'post_title' => $value, - ) - ); - } else { - $meta_key = ( 'prefix_meta_key' === $prefix_meta_key ) ? $prefixed_key : $key; - - if ( ! empty( $meta_id ) ) { - update_metadata_by_mid( 'post', $meta_id, $value, $meta_key ); - } else { - update_post_meta( wcs_get_objects_property( $object, 'id' ), $meta_key, $value ); - } - } + $object->save(); } } @@ -243,9 +201,9 @@ function wcs_delete_objects_property( &$object, $key, $save = 'save', $meta_id = $prefixed_key = wcs_maybe_prefix_key( $key ); - if ( ! empty( $meta_id ) && method_exists( $object, 'delete_meta_data_by_mid' ) ) { + if ( ! empty( $meta_id ) && is_callable( array( $object, 'delete_meta_data_by_mid' ) ) ) { $object->delete_meta_data_by_mid( $meta_id ); - } elseif ( method_exists( $object, 'delete_meta_data' ) ) { + } elseif ( is_callable( array( $object, 'delete_meta_data' ) ) ) { $object->delete_meta_data( $prefixed_key ); } elseif ( isset( $object->$key ) ) { unset( $object->$key ); @@ -253,7 +211,7 @@ function wcs_delete_objects_property( &$object, $key, $save = 'save', $meta_id = // Save the data if ( 'save' === $save ) { - if ( method_exists( $object, 'save' ) ) { // WC 3.0+ + if ( is_callable( array( $object, 'save' ) ) ) { // WC 3.0+ $object->save(); } elseif ( ! empty( $meta_id ) ) { delete_metadata_by_mid( 'post', $meta_id ); @@ -275,7 +233,7 @@ function wcs_delete_objects_property( &$object, $key, $save = 'save', $meta_id = */ function wcs_is_order( $order ) { - if ( method_exists( $order, 'get_type' ) ) { + if ( is_callable( array( $order, 'get_type' ) ) ) { $is_order = ( 'shop_order' === $order->get_type() ); } else { $is_order = ( isset( $order->order_type ) && 'simple' === $order->order_type ); @@ -374,7 +332,7 @@ function wcs_get_coupon_property( $coupon, $property ) { $value = ''; - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $value = $coupon->$property; } else { // Some coupon properties don't map nicely to their corresponding getter function. This array contains those exceptions. @@ -417,7 +375,7 @@ function wcs_get_coupon_property( $coupon, $property ) { */ function wcs_set_coupon_property( &$coupon, $property, $value ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { $coupon->$property = $value; } else { // Some coupon properties don't map nicely to their corresponding setter function. This array contains those exceptions. @@ -522,6 +480,28 @@ function wcs_is_rest_api_request() { return apply_filters( 'woocommerce_is_rest_api_request', $is_rest_api_request ); } +/** + * Determines if the current request is to any or a specific Checkout blocks REST API endpoint. + * + * @see Automattic\WooCommerce\Blocks\StoreApi\RoutesController::initialize() for a list of routes. + * + * @since 1.7.0 + * @param string $endpoint The checkout/checkout blocks endpoint. Optional. Can be empty (any checkout blocks API) or a specific endpoint ('checkout', 'cart', 'products' etc) + * @return bool Whether the current request is for a cart/checkout blocks REST API endpoint. + */ +function wcs_is_checkout_blocks_api_request( $endpoint = '' ) { + + if ( ! wcs_is_rest_api_request() || empty( $_SERVER['REQUEST_URI'] ) ) { + return false; + } + + $endpoint = empty( $endpoint ) ? '' : '/' . $endpoint; + $rest_prefix = trailingslashit( rest_get_url_prefix() ); + $request_uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ); + + return false !== strpos( $request_uri, $rest_prefix . 'wc/store' . $endpoint ); +} + /** * Determines whether the current request is a WordPress cron request. * @@ -578,3 +558,15 @@ function wcs_get_used_coupon_codes( $order ) { function wcs_add_woocommerce_dependent_action( $tag, $function, $woocommerce_version, $operator, $priority = 10, $number_of_args = 1 ) { WCS_Dependent_Hook_Manager::add_woocommerce_dependent_action( $tag, $function, $woocommerce_version, $operator, $priority, $number_of_args ); } + +/** + * Checks if the installed version of WooCommerce is older than a specified version. + * + * @since 4.0.0 + * + * @param string The version string to check in a version_compare() compatible format. + * @return bool Whether the installed version of WC is prior to the given version string. + */ +function wcs_is_woocommerce_pre( $version ) { + return ! defined( 'WC_VERSION' ) || version_compare( WC_VERSION, $version, '<' ); +} diff --git a/includes/wcs-conditional-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-conditional-functions.php similarity index 99% rename from includes/wcs-conditional-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-conditional-functions.php index 0a99c88..affd15c 100644 --- a/includes/wcs-conditional-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-conditional-functions.php @@ -27,3 +27,4 @@ if ( ! defined( 'ABSPATH' ) ) { function wcs_is_order_received_page() { return ( false !== strpos( $_SERVER['REQUEST_URI'], 'order-received' ) ); } + diff --git a/includes/wcs-deprecated-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-deprecated-functions.php similarity index 97% rename from includes/wcs-deprecated-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-deprecated-functions.php index 8cf9799..318efc6 100644 --- a/includes/wcs-deprecated-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-deprecated-functions.php @@ -29,8 +29,8 @@ function wcs_doing_it_wrong( $function, $message, $version ) { if ( function_exists( 'wc_doing_it_wrong' ) ) { wc_doing_it_wrong( $function, $message, $version ); } else { - // Reimplment wc_doing_it_wrong() when WC 3.0 is not active - if ( is_ajax() ) { + // Reimplement wc_doing_it_wrong() when WC 3.0 is not active + if ( wp_doing_ajax() ) { do_action( 'doing_it_wrong_run', $function, $message, $version ); error_log( "{$function} was called incorrectly. {$message}. This message was added in version {$version}." ); } else { @@ -54,8 +54,8 @@ function wcs_deprecated_function( $function, $version, $replacement = null ) { if ( function_exists( 'wc_deprecated_function' ) ) { wc_deprecated_function( $function, $version, $replacement ); } else { - // Reimplment wcs_deprecated_function() when WC 3.0 is not active - if ( is_ajax() ) { + // Reimplement wcs_deprecated_function() when WC 3.0 is not active + if ( wp_doing_ajax() ) { do_action( 'deprecated_function_run', $function, $replacement, $version ); $log_string = "The {$function} function is deprecated since version {$version}."; $log_string .= $replacement ? " Replace with {$replacement}." : ''; @@ -75,7 +75,7 @@ function wcs_deprecated_function( $function, $version, $replacement = null ) { * @param string $message */ function wcs_deprecated_argument( $function, $version, $message = null ) { - if ( is_ajax() ) { + if ( wp_doing_ajax() ) { do_action( 'deprecated_argument_run', $function, $message, $version ); error_log( "{$function} was called with an argument that is deprecated since version {$version}. {$message}" ); } else { @@ -274,7 +274,7 @@ function wcs_deprecated_hook( $hook, $version, $replacement = null, $message = n wc_deprecated_hook( $hook, $version, $replacement, $message ); } else { // Reimplement wcs_deprecated_function() when WC 3.0 is not active - if ( is_ajax() ) { + if ( wp_doing_ajax() ) { do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message ); $message = empty( $message ) ? '' : ' ' . $message; diff --git a/includes/wcs-formatting-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php similarity index 87% rename from includes/wcs-formatting-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php index 32ba76a..4dd7803 100644 --- a/includes/wcs-formatting-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php @@ -135,7 +135,7 @@ function wcs_price_string( $subscription_details ) { $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the last day of each month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string ); } else { // translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up front then $40 on the 23rd of each month") - $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the %4$s of each month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, WC_Subscriptions::append_numeral_suffix( $payment_day ) ); + $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the %4$s of each month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, wcs_append_numeral_suffix( $payment_day ) ); } } else { if ( $payment_day > 27 ) { @@ -143,7 +143,7 @@ function wcs_price_string( $subscription_details ) { $subscription_string = sprintf( __( '%s on the last day of each month', 'woocommerce-subscriptions' ), $recurring_amount_string ); } else { // translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") - $subscription_string = sprintf( __( '%1$s on the %2$s of each month', 'woocommerce-subscriptions' ), $recurring_amount_string, WC_Subscriptions::append_numeral_suffix( $payment_day ) ); + $subscription_string = sprintf( __( '%1$s on the %2$s of each month', 'woocommerce-subscriptions' ), $recurring_amount_string, wcs_append_numeral_suffix( $payment_day ) ); } } } else { @@ -151,18 +151,18 @@ function wcs_price_string( $subscription_details ) { if ( ! empty( $subscription_details['initial_amount'] ) ) { if ( $payment_day > 27 ) { // translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: interval (e.g. "3rd") - $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the last day of every %4$s month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, WC_Subscriptions::append_numeral_suffix( $subscription_details['subscription_interval'] ) ); + $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the last day of every %4$s month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, wcs_append_numeral_suffix( $subscription_details['subscription_interval'] ) ); } else { // translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g. "3rd") - $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the %4$s day of every %5$s month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, WC_Subscriptions::append_numeral_suffix( $payment_day ), WC_Subscriptions::append_numeral_suffix( $subscription_details['subscription_interval'] ) ); + $subscription_string = sprintf( __( '%1$s %2$s then %3$s on the %4$s day of every %5$s month', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, wcs_append_numeral_suffix( $payment_day ), wcs_append_numeral_suffix( $subscription_details['subscription_interval'] ) ); } } else { if ( $payment_day > 27 ) { // translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month") - $subscription_string = sprintf( __( '%1$s on the last day of every %2$s month', 'woocommerce-subscriptions' ), $recurring_amount_string, WC_Subscriptions::append_numeral_suffix( $subscription_details['subscription_interval'] ) ); + $subscription_string = sprintf( __( '%1$s on the last day of every %2$s month', 'woocommerce-subscriptions' ), $recurring_amount_string, wcs_append_numeral_suffix( $subscription_details['subscription_interval'] ) ); } else { // translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") - $subscription_string = sprintf( __( '%1$s on the %2$s day of every %3$s month', 'woocommerce-subscriptions' ), $recurring_amount_string, WC_Subscriptions::append_numeral_suffix( $payment_day ), WC_Subscriptions::append_numeral_suffix( $subscription_details['subscription_interval'] ) ); + $subscription_string = sprintf( __( '%1$s on the %2$s day of every %3$s month', 'woocommerce-subscriptions' ), $recurring_amount_string, wcs_append_numeral_suffix( $payment_day ), wcs_append_numeral_suffix( $subscription_details['subscription_interval'] ) ); } } } @@ -172,19 +172,19 @@ function wcs_price_string( $subscription_details ) { // e.g. $15 on March 15th each year if ( ! empty( $subscription_details['initial_amount'] ) ) { // translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month (e.g. "23rd") - $subscription_string = sprintf( __( '%1$s %2$s then %3$s on %4$s %5$s each year', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], WC_Subscriptions::append_numeral_suffix( $payment_day['day'] ) ); + $subscription_string = sprintf( __( '%1$s %2$s then %3$s on %4$s %5$s each year', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], wcs_append_numeral_suffix( $payment_day['day'] ) ); } else { // translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") - $subscription_string = sprintf( __( '%1$s on %2$s %3$s each year', 'woocommerce-subscriptions' ), $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], WC_Subscriptions::append_numeral_suffix( $payment_day['day'] ) ); + $subscription_string = sprintf( __( '%1$s on %2$s %3$s each year', 'woocommerce-subscriptions' ), $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], wcs_append_numeral_suffix( $payment_day['day'] ) ); } } else { // e.g. $15 on March 15th every 3rd year if ( ! empty( $subscription_details['initial_amount'] ) ) { // translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g. "23rd"), 6$: interval (e.g. "3rd") - $subscription_string = sprintf( __( '%1$s %2$s then %3$s on %4$s %5$s every %6$s year', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], WC_Subscriptions::append_numeral_suffix( $payment_day['day'] ), WC_Subscriptions::append_numeral_suffix( $subscription_details['subscription_interval'] ) ); + $subscription_string = sprintf( __( '%1$s %2$s then %3$s on %4$s %5$s every %6$s year', 'woocommerce-subscriptions' ), $initial_amount_string, $subscription_details['initial_description'], $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], wcs_append_numeral_suffix( $payment_day['day'] ), wcs_append_numeral_suffix( $subscription_details['subscription_interval'] ) ); } else { // translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") - $subscription_string = sprintf( __( '%1$s on %2$s %3$s every %4$s year', 'woocommerce-subscriptions' ), $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], WC_Subscriptions::append_numeral_suffix( $payment_day['day'] ), WC_Subscriptions::append_numeral_suffix( $subscription_details['subscription_interval'] ) ); + $subscription_string = sprintf( __( '%1$s on %2$s %3$s every %4$s year', 'woocommerce-subscriptions' ), $recurring_amount_string, $wp_locale->month[ $payment_day['month'] ], wcs_append_numeral_suffix( $payment_day['day'] ), wcs_append_numeral_suffix( $subscription_details['subscription_interval'] ) ); } } break; @@ -277,3 +277,43 @@ function wp_kses_allow_underscores( $content, $allowed_html ) { $content = wp_kses( $content, $allowed_html ); // Now pass through wp_kses the attribute name with -- return preg_replace( '/\b([-A-Za-z]+)--([-A-Za-z]+)=/', '$1_$2=', $content ); // Replace the _ back } + +/** + * Appends the ordinal suffix to a given number. + * + * eg. Given 2, the function returns 2nd. + * + * @since 4.0.0 + * + * @param string The number to append the ordinal suffix to. + * @return string + */ +function wcs_append_numeral_suffix( $number ) { + + // Handle teens: if the tens digit of a number is 1, then write "th" after the number. For example: 11th, 13th, 19th, 112th, 9311th. http://en.wikipedia.org/wiki/English_numerals + if ( strlen( $number ) > 1 && 1 == substr( $number, -2, 1 ) ) { + // translators: placeholder is a number, this is for the teens + $number_string = sprintf( __( '%sth', 'woocommerce-subscriptions' ), $number ); + } else { // Append relevant suffix + switch ( substr( $number, -1 ) ) { + case 1: + // translators: placeholder is a number, numbers ending in 1 + $number_string = sprintf( __( '%sst', 'woocommerce-subscriptions' ), $number ); + break; + case 2: + // translators: placeholder is a number, numbers ending in 2 + $number_string = sprintf( __( '%snd', 'woocommerce-subscriptions' ), $number ); + break; + case 3: + // translators: placeholder is a number, numbers ending in 3 + $number_string = sprintf( __( '%srd', 'woocommerce-subscriptions' ), $number ); + break; + default: + // translators: placeholder is a number, numbers ending in 4-9, 0 + $number_string = sprintf( __( '%sth', 'woocommerce-subscriptions' ), $number ); + break; + } + } + + return apply_filters( 'woocommerce_numeral_suffix', $number_string, $number ); +} diff --git a/includes/wcs-helper-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php similarity index 90% rename from includes/wcs-helper-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php index 8c2536b..1dec874 100644 --- a/includes/wcs-helper-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-helper-functions.php @@ -62,13 +62,13 @@ function wcs_date_input( $timestamp = 0, $args = array() ) { * @since 2.0 */ function wcs_get_edit_post_link( $post_id ) { - $post_type_object = get_post_type_object( get_post_type( $post_id ) ); + $object = wc_get_order( $post_id ); // works for both WC Order and WC Subscription objects. - if ( ! $post_type_object || ! in_array( $post_type_object->name, array( 'shop_order', 'shop_subscription' ) ) ) { + if ( ! $object || ! in_array( $object->get_type(), array( 'shop_order', 'shop_subscription' ), true ) ) { return; } - return apply_filters( 'get_edit_post_link', admin_url( sprintf( $post_type_object->_edit_link . '&action=edit', $post_id ) ), $post_id, '' ); + return apply_filters( 'get_edit_post_link', $object->get_edit_order_url(), $post_id, '' ); } /** @@ -286,3 +286,28 @@ function wcs_trial_has_passed( $subscription ) { return new WP_Error( 'woocommerce_subscription_invalid_subscription', __( 'Invalid Subscription.', 'woocommerce-subscriptions' ) ); } } + +/** + * Filters an array using a WP filter. + * + * This function behaves similar to PHP's array_filter(), except instead of a callback it uses a filter. + * This allows third-parties via WP filter callbacks to filter the array. + * + * @since 3.1.0 + * + * @param string $filter The WP filter to apply to each element. + * @param array $array The array of items to check. + * @param array $property The name of object's property to check. Optional. Default is '' - the array element value as a boolean will be used, the same as array_filter(). + */ +function wcs_apply_array_filter( $filter, $array, $property = '' ) { + + foreach ( $array as $index => $element ) { + $value = empty( $property ) ? $element : $element->{$property}; + + if ( ! apply_filters( $filter, (bool) $value, $element, $property, $array ) ) { + unset( $array[ $index ] ); + } + } + + return $array; +} diff --git a/includes/wcs-limit-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-limit-functions.php similarity index 100% rename from includes/wcs-limit-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-limit-functions.php diff --git a/includes/wcs-order-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php similarity index 90% rename from includes/wcs-order-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php index 423fcd1..6710f66 100644 --- a/includes/wcs-order-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php @@ -33,11 +33,11 @@ function wcs_get_subscriptions_for_order( $order, $args = array() ) { $subscriptions = array(); - if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { + if ( ! is_a( $order, 'WC_Order' ) ) { $order = wc_get_order( $order ); } - if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { + if ( ! is_a( $order, 'WC_Order' ) ) { return $subscriptions; } @@ -199,7 +199,7 @@ function wcs_copy_order_meta( $from_order, $to_order, $type = 'subscription' ) { $meta = apply_filters( 'wcs_' . $type . '_meta', $meta, $to_order, $from_order ); // Pre WC 3.0 we need to save each meta individually, post 3.0 we can save the object once - $save = WC_Subscriptions::is_woocommerce_pre( '3.0' ) ? 'save' : 'set_prop_only'; + $save = wcs_is_woocommerce_pre( '3.0' ) ? 'save' : 'set_prop_only'; foreach ( $meta as $meta_item ) { wcs_set_objects_property( $to_order, $meta_item['meta_key'], maybe_unserialize( $meta_item['meta_value'] ), $save, '', 'omit_key_prefix' ); @@ -226,11 +226,9 @@ function wcs_create_order_from_subscription( $subscription, $type ) { return $type; } - global $wpdb; - try { - - $wpdb->query( 'START TRANSACTION' ); + $transaction = new WCS_SQL_Transaction(); + $transaction->start(); if ( ! is_object( $subscription ) ) { $subscription = wcs_get_subscription( $subscription ); @@ -248,82 +246,36 @@ function wcs_create_order_from_subscription( $subscription, $type ) { $items = apply_filters( 'wcs_new_order_items', $subscription->get_items( array( 'line_item', 'fee', 'shipping', 'tax', 'coupon' ) ), $new_order, $subscription ); $items = apply_filters( "wcs_{$type}_items", $items, $new_order, $subscription ); - foreach ( $items as $item_index => $item ) { - - $item_name = apply_filters( 'wcs_new_order_item_name', $item['name'], $item, $subscription ); + foreach ( $items as $item ) { + $item_name = apply_filters( 'wcs_new_order_item_name', $item->get_name(), $item, $subscription ); $item_name = apply_filters( "wcs_{$type}_item_name", $item_name, $item, $subscription ); // Create order line item on the renewal order - $order_item_id = wc_add_order_item( wcs_get_objects_property( $new_order, 'id' ), array( + $order_item_id = wc_add_order_item( $new_order->get_id(), array( 'order_item_name' => $item_name, - 'order_item_type' => $item['type'], + 'order_item_type' => $item->get_type(), ) ); - // Remove recurring line items and set item totals based on recurring line totals - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - foreach ( $item['item_meta'] as $meta_key => $meta_values ) { - foreach ( $meta_values as $meta_value ) { - wc_add_order_item_meta( $order_item_id, $meta_key, maybe_unserialize( $meta_value ) ); - } - } - } else { - $order_item = $new_order->get_item( $order_item_id ); + $order_item = $new_order->get_item( $order_item_id ); - wcs_copy_order_item( $item, $order_item ); + wcs_copy_order_item( $item, $order_item ); + $order_item->save(); + + // If the line item we're adding is a product line item and that product still exists, set any applicable backorder meta. + if ( $item->is_type( 'line_item' ) && $item->get_product() ) { + $order_item->set_backorder_meta(); $order_item->save(); } - - // If the line item we're adding is a product line item and that product still exists, trigger the 'woocommerce_order_add_product' hook - if ( 'line_item' == $item['type'] && isset( $item['product_id'] ) ) { - - $product_id = wcs_get_canonical_product_id( $item ); - $product = wc_get_product( $product_id ); - - if ( false !== $product ) { - - $args = array( - 'totals' => array( - 'subtotal' => $item['line_subtotal'], - 'total' => $item['line_total'], - 'subtotal_tax' => $item['line_subtotal_tax'], - 'tax' => $item['line_tax'], - 'tax_data' => maybe_unserialize( $item['line_tax_data'] ), - ), - ); - - // If we have a variation, get the attribute meta data from teh item to pass to callbacks - if ( ! empty( $item['variation_id'] ) && null !== ( $variation_data = wcs_get_objects_property( $product, 'variation_data' ) ) ) { - foreach ( $variation_data as $attribute => $variation ) { - if ( isset( $item[ str_replace( 'attribute_', '', $attribute ) ] ) ) { - $args['variation'][ $attribute ] = $item[ str_replace( 'attribute_', '', $attribute ) ]; - } - } - } - - // Backorders - if ( isset( $order_item ) && is_callable( array( $order_item, 'set_backorder_meta' ) ) ) { // WC 3.0 - $order_item->set_backorder_meta(); - $order_item->save(); - } elseif ( $product->backorders_require_notification() && $product->is_on_backorder( $item['qty'] ) ) { // WC 2.6 - wc_add_order_item_meta( $order_item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce-subscriptions' ) ), $item['qty'] - max( 0, $product->get_total_stock() ) ); - } - - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { - // WC 3.0+ will also trigger the 'woocommerce_order_add_product when 'woocommerce_new_order_item', which is triggered in wc_add_order_item_meta() - do_action( 'woocommerce_order_add_product', wcs_get_objects_property( $new_order, 'id' ), $order_item_id, $product, $item['qty'], $args ); - } - } - } } // If we got here, the subscription was created without problems - $wpdb->query( 'COMMIT' ); + $transaction->commit(); return apply_filters( 'wcs_new_order_created', $new_order, $subscription, $type ); } catch ( Exception $e ) { // There was an error adding the subscription - $wpdb->query( 'ROLLBACK' ); + $transaction->rollback(); return new WP_Error( 'new-order-error', $e->getMessage() ); } } @@ -607,7 +559,7 @@ function wcs_update_order_item_type( $item_id, $new_type, $order_or_subscription * @since 2.0 */ function wcs_get_order_item_meta( $item, $product = null ) { - if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( false === wcs_is_woocommerce_pre( '3.0' ) ) { wcs_deprecated_function( __FUNCTION__, '3.1 of WooCommerce and 2.2.9 of Subscriptions', 'WC_Order_Item_Product->get_formatted_meta_data() or wc_display_item_meta()' ); } return new WC_Order_Item_Meta( $item, $product ); @@ -633,7 +585,7 @@ function wcs_get_order_item_name( $order_item, $include = array() ) { foreach ( $order_item['item_meta'] as $meta_key => $meta_value ) { - $meta_value = WC_Subscriptions::is_woocommerce_pre( 3.0 ) ? $meta_value[0] : $meta_value; + $meta_value = wcs_is_woocommerce_pre( 3.0 ) ? $meta_value[0] : $meta_value; // Skip hidden core fields if ( in_array( $meta_key, apply_filters( 'woocommerce_hidden_order_itemmeta', array( @@ -686,7 +638,7 @@ function wcs_get_line_item_name( $line_item ) { foreach ( $line_item['item_meta'] as $meta_key => $meta_value ) { - $meta_value = WC_Subscriptions::is_woocommerce_pre( 3.0 ) ? $meta_value[0] : $meta_value; + $meta_value = wcs_is_woocommerce_pre( 3.0 ) ? $meta_value[0] : $meta_value; // Skip hidden core fields if ( in_array( $meta_key, apply_filters( 'woocommerce_hidden_order_itemmeta', array( @@ -772,7 +724,7 @@ function wcs_display_item_downloads( $item, $order ) { */ function wcs_copy_order_item( $from_item, &$to_item ) { - if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( wcs_is_woocommerce_pre( '3.0' ) ) { wcs_doing_it_wrong( __FUNCTION__, 'This function uses data structures introduced in WC 3.0. To copy line item meta use $from_item[\'item_meta\'] and wc_add_order_item_meta().', '2.2' ); return; } @@ -805,6 +757,12 @@ function wcs_copy_order_item( $from_item, &$to_item ) { 'total' => $from_item->get_total(), 'taxes' => $from_item->get_taxes(), ) ); + + // Post WC 3.4 the instance ID is stored separately. + if ( ! wcs_is_woocommerce_pre( '3.4' ) ) { + $to_item->set_instance_id( $from_item->get_instance_id() ); + } + break; case 'tax': /** @@ -977,3 +935,29 @@ function wcs_order_contains_product( $order, $product ) { return $order_has_product; } + +/** + * Check if a given order is a subscription renewal order. + * + * @param WC_Order|int $order The WC_Order object or ID of a WC_Order order. + * @since 2.3.0 + * @return bool True if the order contains an early renewal, otherwise false. + */ +function wcs_order_contains_early_renewal( $order ) { + + if ( ! is_object( $order ) ) { + $order = wc_get_order( $order ); + } + + $subscription_id = absint( wcs_get_objects_property( $order, 'subscription_renewal_early' ) ); + $is_early_renewal = wcs_is_order( $order ) && $subscription_id > 0; + + /** + * Allow third-parties to filter whether this order contains the early renewal flag. + * + * @since 2.3.0 + * @param bool $is_renewal True if early renewal meta was found on the order, otherwise false. + * @param WC_Order $order The WC_Order object. + */ + return apply_filters( 'woocommerce_subscriptions_is_early_renewal_order', $is_early_renewal, $order ); +} diff --git a/includes/wcs-product-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php similarity index 95% rename from includes/wcs-product-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php index 0c3c17a..fe77559 100644 --- a/includes/wcs-product-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php @@ -185,7 +185,7 @@ function wcs_calculate_min_max_variations( $variations_data ) { // Determine some recurring price flags $is_lowest_price = $variation_data['price'] < $lowest_price || '' === $lowest_price; - $is_longest_period = WC_Subscriptions::get_longest_period( $variable_subscription_period, $variation_data['subscription']['period'] ) === $variation_data['subscription']['period']; + $is_longest_period = wcs_get_longest_period( $variable_subscription_period, $variation_data['subscription']['period'] ) === $variation_data['subscription']['period']; $is_longest_interval = $variation_data['subscription']['interval'] >= $variable_subscription_period_interval || '' === $variable_subscription_period_interval; // Find the amount the subscriber will have to pay up-front @@ -236,7 +236,7 @@ function wcs_calculate_min_max_variations( $variations_data ) { $is_min = $variation_data['subscription']['trial_length'] > $variable_subscription_trial_length; // Otherwise just a longer trial period (that isn't equal to the longest period) - } elseif ( WC_Subscriptions::get_longest_period( $longest_trial_period, $variation_data['subscription']['trial_period'] ) === $variation_data['subscription']['trial_period'] ) { + } elseif ( wcs_get_longest_period( $longest_trial_period, $variation_data['subscription']['trial_period'] ) === $variation_data['subscription']['trial_period'] ) { $is_min = true; @@ -260,7 +260,7 @@ function wcs_calculate_min_max_variations( $variations_data ) { $is_max = $variation_data['subscription']['trial_length'] < $shortest_trial_length; // Need to find shortest period - } elseif ( WC_Subscriptions::get_shortest_period( $shortest_trial_period, $variation_data['subscription']['trial_period'] ) === $variation_data['subscription']['trial_period'] ) { + } elseif ( wcs_get_shortest_period( $shortest_trial_period, $variation_data['subscription']['trial_period'] ) === $variation_data['subscription']['trial_period'] ) { $is_max = true; @@ -273,8 +273,8 @@ function wcs_calculate_min_max_variations( $variations_data ) { } } else { - $longest_initial_period = WC_Subscriptions::get_longest_period( $longest_initial_period, $initial_period ); - $shortest_initial_period = WC_Subscriptions::get_shortest_period( $shortest_initial_period, $initial_period ); + $longest_initial_period = wcs_get_longest_period( $longest_initial_period, $initial_period ); + $shortest_initial_period = wcs_get_shortest_period( $shortest_initial_period, $initial_period ); $is_lowest_initial_amount = $initial_amount < $lowest_initial_amount || '' === $lowest_initial_amount; $is_longest_initial_period = $initial_period === $longest_initial_period; diff --git a/includes/wcs-renewal-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php similarity index 87% rename from includes/wcs-renewal-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php index 6514699..0ca717c 100644 --- a/includes/wcs-renewal-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php @@ -141,3 +141,23 @@ function wcs_get_last_non_early_renewal_order( $subscription ) { return $last_non_early_renewal; } + +/** + * Checks if manual renewals are required - automatic renewals are disabled. + * + * @since 4.0.0 + * @return bool Weather manual renewal are required. + */ +function wcs_is_manual_renewal_required() { + return class_exists( 'WCS_Manual_Renewal_Manager' ) ? WCS_Manual_Renewal_Manager::is_manual_renewal_required() : false; +} + +/** + * Checks if manual renewals are enabled. + * + * @since 4.0.0 + * @return bool Weather manual renewal are enabled. + */ +function wcs_is_manual_renewal_enabled() { + return class_exists( 'WCS_Manual_Renewal_Manager' ) ? WCS_Manual_Renewal_Manager::is_manual_renewal_enabled() : false; +} diff --git a/includes/wcs-resubscribe-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-resubscribe-functions.php similarity index 100% rename from includes/wcs-resubscribe-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-resubscribe-functions.php diff --git a/includes/wcs-switch-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php similarity index 79% rename from includes/wcs-switch-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php index a29431e..6f1c60b 100644 --- a/includes/wcs-switch-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php @@ -113,3 +113,25 @@ function wcs_is_product_switchable_type( $product ) { return apply_filters( 'wcs_is_product_switchable', $is_product_switchable, $product, $variation ); } + +/** + * Check if the cart includes any items which are to switch an existing subscription's contents. + * + * @since 4.0.0 + * @param string $item_action Types of items to include ("any", "switch", or "add"). + * @return bool|array Returns cart items that modify subscription contents, or false if no such items exist. + */ +function wcs_cart_contains_switches( $item_action = 'any' ) { + return class_exists( 'WC_Subscriptions_Switcher' ) ? WC_Subscriptions_Switcher::cart_contains_switches( $item_action ) : false; +} + +/** + * Gets the switch direction of a cart item. + * + * @since 4.0.0 + * @param array $cart_item Cart item object. + * @return string|null Cart item subscription switch direction or null. + */ +function wcs_get_cart_item_switch_type( $cart_item ) { + return class_exists( 'WC_Subscriptions_Switcher' ) ? WC_Subscriptions_Switcher::get_cart_item_switch_type( $cart_item ) : null; +} diff --git a/includes/wcs-time-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php similarity index 94% rename from includes/wcs-time-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php index 2de6fe9..c0ff897 100644 --- a/includes/wcs-time-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php @@ -127,15 +127,19 @@ function wcs_get_non_cached_subscription_ranges() { * @return bool|mixed */ function wcs_get_subscription_ranges( $subscription_period = '' ) { + static $subscription_locale_ranges = array(); + if ( ! is_string( $subscription_period ) ) { $subscription_period = ''; } $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale(); - $subscription_ranges = WC_Subscriptions::$cache->cache_and_get( 'wcs-sub-ranges-' . $locale, 'wcs_get_non_cached_subscription_ranges', array(), 3 * HOUR_IN_SECONDS ); + if ( ! isset( $subscription_locale_ranges[ $locale ] ) ) { + $subscription_locale_ranges[ $locale ] = wcs_get_non_cached_subscription_ranges(); + } - $subscription_ranges = apply_filters( 'woocommerce_subscription_lengths', $subscription_ranges, $subscription_period ); + $subscription_ranges = apply_filters( 'woocommerce_subscription_lengths', $subscription_locale_ranges[ $locale ], $subscription_period ); if ( ! empty( $subscription_period ) ) { return $subscription_ranges[ $subscription_period ]; @@ -156,7 +160,7 @@ function wcs_get_subscription_period_interval_strings( $interval = '' ) { foreach ( range( 2, 6 ) as $i ) { // translators: period interval, placeholder is ordinal (eg "$10 every _2nd/3rd/4th_", etc) - $intervals[ $i ] = sprintf( _x( 'every %s', 'period interval with ordinal number (e.g. "every 2nd"', 'woocommerce-subscriptions' ), WC_Subscriptions::append_numeral_suffix( $i ) ); + $intervals[ $i ] = sprintf( _x( 'every %s', 'period interval with ordinal number (e.g. "every 2nd"', 'woocommerce-subscriptions' ), wcs_append_numeral_suffix( $i ) ); } $intervals = apply_filters( 'woocommerce_subscription_period_interval_strings', $intervals ); @@ -877,3 +881,53 @@ function wcs_format_datetime( $date, $format = '' ) { return $formatted_datetime; } + +/** + * Compares two periods and returns the longest period. + * + * @since 4.0.0 + * + * @param string $current_period Period string. Can be 'day', 'week', 'month', 'year'. + * @param string $new_period Period string. Can be 'day', 'week', 'month', 'year'. + * + * @return string The longest period between the two provided. + */ +function wcs_get_longest_period( $current_period, $new_period ) { + + if ( empty( $current_period ) || 'year' == $new_period ) { + $longest_period = $new_period; + } elseif ( 'month' === $new_period && in_array( $current_period, array( 'week', 'day' ) ) ) { + $longest_period = $new_period; + } elseif ( 'week' === $new_period && 'day' === $current_period ) { + $longest_period = $new_period; + } else { + $longest_period = $current_period; + } + + return $longest_period; +} + +/** + * Compares two periods and returns the shortest period. + * + * @since 4.0.0 + * + * @param string $current_period A period string. Can be 'day', 'week', 'month', 'year'. + * @param string $new_period A period string. Can be 'day', 'week', 'month', 'year'. + * + * @return string The shortest period between the two provided. + */ +function wcs_get_shortest_period( $current_period, $new_period ) { + + if ( empty( $current_period ) || 'day' == $new_period ) { + $shortest_period = $new_period; + } elseif ( 'week' === $new_period && in_array( $current_period, array( 'month', 'year' ) ) ) { + $shortest_period = $new_period; + } elseif ( 'month' === $new_period && 'year' === $current_period ) { + $shortest_period = $new_period; + } else { + $shortest_period = $current_period; + } + + return $shortest_period; +} diff --git a/includes/wcs-user-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php similarity index 88% rename from includes/wcs-user-functions.php rename to vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php index 29a09b7..6d1d210 100644 --- a/includes/wcs-user-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php @@ -102,8 +102,8 @@ function wcs_update_users_role( $user_id, $role_new ) { * @return array with keys 'old' and 'new'. */ function wcs_get_new_user_role_names( $role_new ) { - $default_subscriber_role = get_option( WC_Subscriptions_Admin::$option_prefix . '_subscriber_role' ); - $default_cancelled_role = get_option( WC_Subscriptions_Admin::$option_prefix . '_cancelled_role' ); + $default_subscriber_role = wcs_get_subscriber_role(); + $default_cancelled_role = wcs_get_inactive_subscriber_role(); $role_old = ''; if ( 'default_subscriber_role' == $role_new ) { @@ -273,7 +273,6 @@ function wcs_get_users_change_status_link( $subscription_id, $status, $current_s * @since 2.0 */ function wcs_can_user_put_subscription_on_hold( $subscription, $user = '' ) { - $user_can_suspend = false; if ( empty( $user ) ) { @@ -283,29 +282,10 @@ function wcs_can_user_put_subscription_on_hold( $subscription, $user = '' ) { } if ( user_can( $user, 'manage_woocommerce' ) ) { // Admin, so can always suspend a subscription - $user_can_suspend = true; - - } else { // Need to make sure user owns subscription & the suspension limit hasn't been reached - - if ( ! is_object( $subscription ) ) { - $subscription = wcs_get_subscription( $subscription ); - } - - // Make sure current user owns subscription - if ( $user->ID == $subscription->get_user_id() ) { - - // Make sure subscription suspension count hasn't been reached - $suspension_count = intval( $subscription->get_suspension_count() ); - $allowed_suspensions = get_option( WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions', 0 ); - - if ( 'unlimited' === $allowed_suspensions || $allowed_suspensions > $suspension_count ) { // 0 not > anything so prevents a customer ever being able to suspend - $user_can_suspend = true; - } - } } - return apply_filters( 'wcs_can_user_put_subscription_on_hold', $user_can_suspend, $subscription ); + return apply_filters( 'wcs_can_user_put_subscription_on_hold', $user_can_suspend, $subscription, $user ); } /** @@ -323,16 +303,9 @@ function wcs_get_all_user_actions_for_subscription( $subscription, $user_id ) { $actions = array(); if ( user_can( $user_id, 'edit_shop_subscription_status', $subscription->get_id() ) ) { - - $admin_with_suspension_disallowed = current_user_can( 'manage_woocommerce' ) && '0' === get_option( WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions', '0' ); $current_status = $subscription->get_status(); - if ( $subscription->can_be_updated_to( 'on-hold' ) && wcs_can_user_put_subscription_on_hold( $subscription, $user_id ) && ! $admin_with_suspension_disallowed ) { - $actions['suspend'] = array( - 'url' => wcs_get_users_change_status_link( $subscription->get_id(), 'on-hold', $current_status ), - 'name' => __( 'Suspend', 'woocommerce-subscriptions' ), - ); - } elseif ( $subscription->can_be_updated_to( 'active' ) && ! $subscription->needs_payment() ) { + if ( $subscription->can_be_updated_to( 'active' ) && ! $subscription->needs_payment() ) { $actions['reactivate'] = array( 'url' => wcs_get_users_change_status_link( $subscription->get_id(), 'active', $current_status ), 'name' => __( 'Reactivate', 'woocommerce-subscriptions' ), @@ -356,7 +329,7 @@ function wcs_get_all_user_actions_for_subscription( $subscription, $user_id ) { } } - return apply_filters( 'wcs_view_subscription_actions', $actions, $subscription ); + return apply_filters( 'wcs_view_subscription_actions', $actions, $subscription, $user_id ); } /** @@ -448,8 +421,38 @@ add_filter( 'user_has_cap', 'wcs_user_has_capability', 15, 3 ); * @return array The list of roles editable by shop managers. */ function wcs_grant_shop_manager_editable_roles( $roles ) { - $roles[] = get_option( WC_Subscriptions_Admin::$option_prefix . '_subscriber_role' ); + $roles[] = wcs_get_subscriber_role(); return $roles; } add_filter( 'woocommerce_shop_manager_editable_roles', 'wcs_grant_shop_manager_editable_roles' ); + +/** + * Gets the subscriber role. + * + * @since 4.0.0 + * + * @return string The role to apply to subscribers. + */ +function wcs_get_subscriber_role() { + if ( class_exists( 'WCS_Subscriber_Role_Manager' ) ) { + return WCS_Subscriber_Role_Manager::get_subscriber_role(); + } + + return 'subscriber'; +} + +/** + * Gets the inactive subscriber role. + * + * @since 4.0.0 + * + * @return string The role to apply to inactive subscribers. + */ +function wcs_get_inactive_subscriber_role() { + if ( class_exists( 'WCS_Subscriber_Role_Manager' ) ) { + return WCS_Subscriber_Role_Manager::get_inactive_subscriber_role(); + } + + return 'customer'; +} diff --git a/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions-fr.mo b/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions-fr.mo new file mode 100644 index 0000000..d7c119a Binary files /dev/null and b/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions-fr.mo differ diff --git a/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions-fr.po b/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions-fr.po new file mode 100644 index 0000000..a4694f5 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions-fr.po @@ -0,0 +1,8189 @@ +# Translation of WooCommerce - WooCommerce Subscriptions in French (France) +# This file is distributed under the same license as the WooCommerce - WooCommerce Subscriptions package. +msgid "" +msgstr "" +"PO-Revision-Date: 2020-11-06 17:52:37+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: GlotPress/2.4.0-alpha\n" +"Language: fr\n" +"Project-Id-Version: WooCommerce - WooCommerce Subscriptions\n" + +#: includes/class-wc-subscriptions-order.php:517 +msgid "Payment completed on order after subscription was cancelled." +msgstr "" + +#. Translators: Placeholder is the subscription ID number. +#: includes/class-wc-subscriptions-manager.php:917 +msgid "" +"The related subscription #%s has been deleted after the customer was deleted." +msgstr "" + +#. Translators: 1: The subscription ID number. 2: The current user's username. +#: includes/class-wc-subscriptions-manager.php:914 +msgid "" +"The related subscription #%1$s has been deleted after the customer was " +"deleted by %2$s." +msgstr "" + +#: templates/checkout/recurring-totals.php:19 +msgid "Recurring totals" +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: includes/class-wc-subscriptions-checkout.php:569 +msgid "" +"Purchasing a subscription product requires an account. Please go to the %sMy " +"Account%s page to login or contact us if you need assistance." +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: includes/class-wc-subscriptions-checkout.php:566 +msgid "" +"Purchasing a subscription product requires an account. Please go to the %sMy " +"Account%s page to login or register." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:384 +msgid "Lock manual price increases" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:380 +msgid "" +"This order contains line items with prices above the current product price. " +"To override the product's live price when the customer pays for this order, " +"lock in the manual price increases." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:124 +msgid "Please enter a date at least 2 minutes into the future." +msgstr "" + +#: templates/myaccount/subscription-details.php:62 +msgid "Using the auto-renewal toggle is disabled while in staging mode." +msgstr "" +"L’utilisation de la bascule de renouvellement automatique est désactivée en " +"mode préproduction." + +#: templates/myaccount/subscription-details.php:24 +msgctxt "customer subscription table header" +msgid "Start date" +msgstr "Date de début" + +#: templates/myaccount/related-orders.php:15 +msgid "Related orders" +msgstr "Commandes similaires" + +#: templates/myaccount/my-subscriptions.php:77 +msgid "Browse products" +msgstr "Parcourir les produits" + +#: templates/myaccount/my-subscriptions.php:74 +msgid "You have no active subscriptions." +msgstr "Vous n’avez pas d’abonnement actif." + +#: templates/html-early-renewal-modal-content.php:34 +msgid "Want to renew early via the checkout? Click %shere.%s" +msgstr "" +"Vous voulez renouveler tôt via la validation de commande ? Cliquez %sici.%s" + +#: templates/html-early-renewal-modal-content.php:28 +msgid "" +"By renewing your subscription early, your scheduled next payment on %s will " +"be cancelled." +msgstr "" +"En renouvelant votre abonnement tôt, votre prochain paiement planifié le %s " +"sera annulé." + +#: templates/html-early-renewal-modal-content.php:23 +msgid "By renewing your subscription early your next payment will be %s." +msgstr "En renouvelant votre abonnement tôt, votre prochain paiement sera %s." + +#. Translators: Placeholders are opening and closing My Account link tags. +#: templates/emails/subscription-info.php:57 +msgid "" +"This subscription is set to renew automatically using your payment method on " +"file. You can manage or cancel this subscription from your %smy account " +"page%s." +msgid_plural "" +"These subscriptions are set to renew automatically using your payment method " +"on file. You can manage or cancel your subscriptions from your %smy account " +"page%s." +msgstr[0] "" +"Cet abonnement est configuré pour se renouveler automatiquement en utilisant " +"votre moyen de paiement enregistré. Vous pouvez gérer ou annuler cet " +"abonnement sur votre %spage Mon compte%s." +msgstr[1] "" +"Ces abonnements sont configurés pour se renouveler automatiquement en " +"utilisant votre moyen de paiement enregistré. Vous pouvez gérer ou annuler " +"vos abonnements sur votre %spage Mon compte%s." + +#: templates/emails/subscription-info.php:37 +msgctxt "Used as end date for an indefinite subscription" +msgid "When cancelled" +msgstr "En cas d’annulation" + +#: templates/emails/subscription-info.php:28 +msgctxt "table heading" +msgid "Recurring total" +msgstr "Total récurrent" + +#: templates/emails/subscription-info.php:27 +msgctxt "table heading" +msgid "End date" +msgstr "Date de fin" + +#: templates/emails/subscription-info.php:26 +msgctxt "table heading" +msgid "Start date" +msgstr "Date de début" + +#: templates/emails/subscription-info.php:25 +msgctxt "subscription ID table heading" +msgid "ID" +msgstr "ID" + +#. Translators: Placeholder is the My Account URL. +#: templates/emails/plain/subscription-info.php:51 +msgid "" +"This subscription is set to renew automatically using your payment method on " +"file. You can manage or cancel this subscription from your my account page. " +"%s" +msgid_plural "" +"These subscriptions are set to renew automatically using your payment method " +"on file. You can manage or cancel your subscriptions from your my account " +"page. %s" +msgstr[0] "" +"Cet abonnement est configuré pour se renouveler automatiquement en utilisant " +"votre moyen de paiement enregistré. Vous pouvez gérer ou annuler cet " +"abonnement sur votre page Mon compte. %s" +msgstr[1] "" +"Ces abonnements sont configurés pour se renouveler automatiquement en " +"utilisant votre moyen de paiement enregistré. Vous pouvez gérer ou annuler " +"vos abonnements sur votre page Mon compte. %s" + +#: templates/emails/plain/subscription-info.php:38 +#: templates/emails/subscription-info.php:42 +msgid "Next payment: %s" +msgstr "Paiement suivant : %s" + +#. translators: placeholder is either view or edit url for the subscription +#: templates/emails/plain/subscription-info.php:27 +msgctxt "in plain emails for subscription information" +msgid "View subscription: %s" +msgstr "Afficher l’abonnement : %s" + +#: templates/emails/email-order-details.php:61 +msgid "Note:" +msgstr "Remarque :" + +#. translators: %s: Order number +#: templates/emails/customer-processing-renewal-order.php:19 +#: templates/emails/plain/customer-processing-renewal-order.php:18 +msgid "" +"Just to let you know — we've received your subscription renewal order " +"#%s, and it is now being processed:" +msgstr "" +"Pour information – nous avons reçu votre commande de renouvellement " +"d’abonnement n° %s, elle est maintenant en cours de traitement :" + +#: templates/emails/customer-on-hold-renewal-order.php:18 +#: templates/emails/plain/customer-on-hold-renewal-order.php:17 +msgid "" +"Thanks for your renewal order. It’s on-hold until we confirm that payment " +"has been received. In the meantime, here’s a reminder of your order:" +msgstr "" +"Merci pour votre commande de renouvellement. Elle est en attente jusqu’à ce " +"que nous confirmions que le paiement ait bien été reçu. En attendant, voici " +"un rappel de votre commande :" + +#: templates/emails/customer-completed-renewal-order.php:18 +#: templates/emails/plain/customer-completed-renewal-order.php:17 +msgid "We have finished processing your subscription renewal order." +msgstr "" +"Nous avons terminé de traiter votre commande de renouvellement d’abonnement." + +#. translators: %s: Customer first name +#: templates/emails/customer-completed-renewal-order.php:17 +#: templates/emails/customer-completed-switch-order.php:17 +#: templates/emails/customer-on-hold-renewal-order.php:17 +#: templates/emails/customer-payment-retry.php:16 +#: templates/emails/customer-processing-renewal-order.php:17 +#: templates/emails/customer-renewal-invoice.php:16 +#: templates/emails/plain/customer-completed-renewal-order.php:16 +#: templates/emails/plain/customer-completed-switch-order.php:16 +#: templates/emails/plain/customer-on-hold-renewal-order.php:16 +#: templates/emails/plain/customer-payment-retry.php:16 +#: templates/emails/plain/customer-processing-renewal-order.php:16 +#: templates/emails/plain/customer-renewal-invoice.php:16 +msgid "Hi %s," +msgstr "Salut %s," + +#. translators: 1) passed sort order type argument, 2) 'ascending', 3) +#. 'descending'. +#: includes/wcs-helper-functions.php:266 +msgid "" +"Invalid sort order type: %1$s. The $sort_order argument must be %2$s or %3$s." +msgstr "" +"Type d’ordre de tri non valide : %1$s. L’argument $sort_order doit être %2$s " +"ou %3$s." + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/templates/update-welcome-notice.php:16 +msgid "Want to know more about Subscriptions %s?" +msgstr "Vous désirez en savoir plus sur Subscriptions %s ?" + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:99 +msgid "Welcome to WooCommerce Subscriptions %s!" +msgstr "Bienvenue dans WooCommerce Subscriptions %s !" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:92 +msgid "" +"Previous versions of Subscriptions relied on %1$sWP Cron%2$s to process " +"subscription payments and other scheduled events. In 3.0, these events will " +"now run on admin request with loopback support. This will significantly " +"increase the throughput of payment processing." +msgstr "" +"Les versions précédentes de Subscriptions reposaient sur %1$sWP Cron%2$s " +"pour traiter les paiements d’abonnements et d’autres événements planifiés. " +"Dans la version 3.0, ces événements s’exécuteront désormais à la demande de " +"l’administrateur avec prise en charge du bouclage. Cela augmentera " +"considérablement le débit du traitement des paiements." + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:89 +msgid "Increased processing rate for scheduled payments" +msgstr "Augmentation du taux de traitement des paiements planifiés" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:86 +msgid "" +"Scheduled action data, which was previously stored in the WordPress post " +"tables, has been moved to a custom database table. Amongst other benefits, " +"this will greatly improve the performance of processing scheduled actions " +"such as subscription payments." +msgstr "" +"Les données des actions planifiées, qui étaient auparavant stockées dans les " +"tables d’articles WordPress, ont été déplacées dans une table de base de " +"données personnalisée. Entre autres avantages, cela améliorera " +"considérablement les performances du traitement des actions planifiées " +"telles que les paiements d’abonnement." + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:85 +msgid "Improved scheduled action data storage" +msgstr "Stockage amélioré des données des actions planifiées" + +#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:29 +msgid "" +"To resolve this as quickly as possible, please create a %1$stemporary " +"administrator account%3$s with the user email woologin@woocommerce.com and " +"share the credentials with us via %2$sQuickForget.com%3$s." +msgstr "" +"Pour résoudre ceci le plus rapidement possible, veuillez créer un %1$scompte " +"d’administrateur temporaire%3$s avec l’adresse e-mail d’utilisateur " +"woologin@woocommerce.com et partager les identifiants de connexion avec nous " +"via %2$sQuickForget.com%3$s." + +#. translators: opening/closing tags - links to documentation. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:126 +msgid "" +"%1$sPayPal Reference Transactions are not enabled on your account%2$s. If " +"you wish to use PayPal Reference Transactions with Subscriptions, please " +"contact PayPal and request they %3$senable PayPal Reference Transactions%4$s " +"on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" +"%1$sPayPal Reference Transactions n’est pas activé sur votre compte%2$s. Si " +"vous souhaitez utiliser PayPal Reference Transactions avec Subscriptions, " +"veuillez contacter PayPal et leur demander d’%3$sactiver PayPal Reference " +"Transactions%4$s sur votre compte. %5$sVérifier le compte PayPal%6$s %3$sEn " +"savoir plus%7$s" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:135 +msgid "" +"Sorry, it seems there are no available payment methods which support " +"subscriptions. Please see %1$sEnabling Payment Gateways for " +"Subscriptions%2$s if you require assistance." +msgstr "" +"Désolé, il semble qu’aucun mode de paiement ne soit disponible pour les " +"abonnements. Veuillez consulter %1$sActiver des passerelles de paiement pour " +"Subscriptions%2$s si vous avez besoin d’aide." + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:26 +msgid "Thank you for your renewal order" +msgstr "Merci pour votre commande de renouvellement" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:25 +msgid "Your {blogname} renewal order has been received!" +msgstr "Votre commande de renouvellement de {blogname} a été reçue !" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:24 +msgid "" +"This is an order notification sent to customers containing order details " +"after a renewal order is placed on-hold." +msgstr "" +"Ceci est une notification de commande envoyée aux clients après qu’une " +"commande de renouvellement est placée en attente et contenant les détails de " +"la commande." + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:23 +msgid "On-hold Renewal Order" +msgstr "Commande de renouvellement en attente" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:153 +msgid "Your early renewal order was successful." +msgstr "Votre commande de renouvellement anticipé a réussi." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:145 +msgid "" +"Payment for the renewal order was unsuccessful with your payment method on " +"file, please try again." +msgstr "" +"Le paiement de la commande de renouvellement a échoué avec votre moyen de " +"paiement enregistré, veuillez réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:128 +msgid "" +"We couldn't create a renewal order for your subscription, please try again." +msgstr "" +"Nous n’avons pas pu créer de commande de renouvellement pour votre " +"abonnement, veuillez réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:118 +msgid "You can't renew the subscription at this time. Please try again." +msgstr "" +"Vous ne pouvez pas renouveler l’abonnement pour le moment. Veuillez " +"réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:113 +msgid "We were unable to locate that subscription, please try again." +msgstr "Nous n’avons pas pu localiser cet abonnement, veuillez réessayer." + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:56 +msgid "Renew early" +msgstr "Renouveler tôt" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:39 +msgid "Pay now" +msgstr "Payer maintenant" + +#. translators: 1-2: opening/closing tags , 2-3: opening/closing tags +#. for a link to docs on early renewal. +#: includes/early-renewal/class-wcs-early-renewal-manager.php:66 +msgid "" +"Allow customers to bypass the checkout and renew their subscription early " +"from their %1$sMy Account > View Subscription%2$s page. %3$sLearn more.%4$s" +msgstr "" +"Autorisez les clients à contourner la validation de commande et à renouveler " +"leur abonnement tôt sur la page %1$sMon compte > Afficher l’abonnement%2$s. " +"%3$sEn savoir plus.%4$s" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:63 +msgid "Accept Early Renewal Payments via a Modal" +msgstr "Accepter les paiements de renouvellement anticipé via un modal" + +#: includes/class-wcs-switch-totals-calculator.php:196 +msgid "" +"Your cart contained an invalid subscription switch request. It has been " +"removed from your cart." +msgstr "" +"Votre panier contenait une demande de changement d’abonnement non valide. " +"Elle a été supprimée de votre panier." + +#. translators: placeholder is a payment method title. +#: includes/class-wcs-staging.php:97 +msgid "" +"Subscription locked to Manual Renewal while the store is in staging mode. " +"Live payment method: %s" +msgstr "" +"Abonnement verrouillé sur Renouvellement manuel pendant que la boutique est " +"en mode préproduction. Moyen de paiement en direct : %s" + +#: includes/class-wcs-staging.php:83 +msgid "" +"Subscription locked to Manual Renewal while the store is in staging mode. " +"Payment method changes will take effect in live mode." +msgstr "" +"Abonnement verrouillé sur Renouvellement manuel pendant que la boutique est " +"en mode préproduction. Les changements de moyen de paiement prendront effet " +"en mode en direct." + +#. translators: %s is order's number +#: includes/class-wcs-cart-renewal.php:330 +msgid "Order #%s has not been added to the cart." +msgstr "La commande n°%s n’a pas été ajoutée au panier." + +#. translators: %s: new item name. +#: includes/class-wc-subscriptions-switcher.php:1988 +msgctxt "used in order notes" +msgid "Customer added %s." +msgstr "Le client a ajouté %s." + +#: includes/class-wc-subscriptions-manager.php:134 +msgid "Manual renewal order awaiting customer payment." +msgstr "Commande de renouvellement manuel en attente de paiement client." + +#. translators: %1$s is the coupon code, %2$d is the number of payment usages +#: includes/class-wc-subscriptions-coupon.php:1047 +msgid "" +"Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d " +"time." +msgid_plural "" +"Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d " +"times." +msgstr[0] "" +"Le code de promotion à usage limité « %1$s » a été supprimé de l’abonnement. " +"Il a été utilisé %2$d fois." +msgstr[1] "" +"Le code de promotion à usage limité « %1$s » a été supprimé de l’abonnement. " +"Il a été utilisé %2$d fois." + +#: includes/class-wc-subscriptions-cart-validator.php:111 +msgid "" +"Your cart has been emptied of subscription products. Only one subscription " +"product can be purchased at a time." +msgstr "" +"Des produits d’abonnement ont été retirés de votre panier. Un seul produit " +"d’abonnement peut être acheté à la fois." + +#: includes/class-wc-product-subscription.php:73 +msgid "Read more" +msgstr "Lire plus" + +#: includes/api/class-wc-rest-subscriptions-controller.php:691 +msgid "Meta value." +msgstr "Valeur de la méta." + +#: includes/api/class-wc-rest-subscriptions-controller.php:685 +msgid "Meta label." +msgstr "Etiquette de la méta." + +#: includes/api/class-wc-rest-subscriptions-controller.php:679 +msgid "Meta key." +msgstr "Clé de la méta." + +#: includes/api/class-wc-rest-subscriptions-controller.php:671 +msgid "Removed line item meta data." +msgstr "Métadonnées de l'article de la ligne supprimées." + +#: includes/api/class-wc-rest-subscriptions-controller.php:662 +msgid "Tax subtotal." +msgstr "Sous-total de la TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:656 +msgid "Tax total." +msgstr "Total de la TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:650 +msgid "Tax rate ID." +msgstr "ID du taux de TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:642 +msgid "Line taxes." +msgstr "Ligne de TVA." + +#: includes/api/class-wc-rest-subscriptions-controller.php:637 +msgid "Line total tax (after discounts)." +msgstr "Ligne de total de TVA (après remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:632 +msgid "Line total (after discounts)." +msgstr "Ligne de total (après remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:627 +msgid "Line subtotal tax (before discounts)." +msgstr "Ligne de sous-total de TVA (avant remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:622 +msgid "Line subtotal (before discounts)." +msgstr "Ligne de sous-total (avant remises)." + +#: includes/api/class-wc-rest-subscriptions-controller.php:616 +msgid "Product price." +msgstr "Tarif du produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:610 +msgid "Tax class of product." +msgstr "Classe de TVA de produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:605 +msgid "Quantity ordered." +msgstr "Quantité commandé." + +#: includes/api/class-wc-rest-subscriptions-controller.php:600 +msgid "Variation ID, if applicable." +msgstr "ID de la variation, si applicable." + +#: includes/api/class-wc-rest-subscriptions-controller.php:595 +msgid "Product ID." +msgstr "ID produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:589 +msgid "Product SKU." +msgstr "UGS du produit." + +#: includes/api/class-wc-rest-subscriptions-controller.php:583 +msgid "Product name." +msgstr "Nom du produit" + +#: includes/api/class-wc-rest-subscriptions-controller.php:577 +msgid "Item ID." +msgstr "ID de l’article." + +#: includes/api/class-wc-rest-subscriptions-controller.php:570 +msgid "Removed line items data." +msgstr "Données articles de la ligne supprimées." + +#: includes/api/class-wc-rest-subscriptions-controller.php:497 +msgid "" +"The status to transition the subscription to. Unlike the \"status\" param, " +"this will calculate and update the subscription dates." +msgstr "" +"État vers lequel effectuer la transition de l’abonnement. Contrairement au " +"paramètre « état », cela calculera et mettra à jour les dates d’abonnement." + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:97 +msgid "" +"The number of upcoming renewal orders, for currently active subscriptions." +msgstr "" +"Nombre de commandes de renouvellement à venir, pour les abonnements " +"actuellement actifs." + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:90 +msgid "" +"The sum of all the upcoming renewal orders, including items, fees, tax and " +"shipping, for currently active subscriptions." +msgstr "" +"Somme de toutes les commandes de renouvellement à venir, incluant les " +"articles, les frais, les frais d’expédition et de taxe, pour les abonnements " +"actuellement actifs." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:1024 +msgid "Switch Totals" +msgstr "Totaux de changements" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:678 +msgid "%2$s %1$s current subscriptions" +msgstr "%2$s %1$s abonnements actuels" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:653 +msgid "%2$s %1$s ended subscriptions" +msgstr "%2$s %1$s abonnements terminés" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:631 +msgid "%2$s %1$s subscription cancellations" +msgstr "%2$s %1$s annulations d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:609 +msgid "%2$s %1$s subscription switches" +msgstr "%2$s %1$s changements d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:587 +msgid "%2$s %1$s subscription renewals" +msgstr "%2$s %1$s renouvellements d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:565 +msgid "%2$s %1$s subscription resubscribes" +msgstr "%2$s %1$s réabonnements d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:543 +msgid "%2$s %1$s subscription signups" +msgstr "%2$s %1$s inscriptions d’abonnement" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:521 +msgid "%2$s %1$s new subscriptions" +msgstr "%2$s %1$s nouveaux abonnements" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:513 +msgid "The sum of all switch orders including tax and shipping." +msgstr "" +"Somme de toutes les commandes de changement, incluant les frais d’expédition " +"et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:512 +msgid "%s switch revenue in this period" +msgstr "%s revenu de changement sur cette période" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:232 +msgid "Copy billing address" +msgstr "Copier l’adresse de facturation" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 +msgid "Billing" +msgstr "Facturation" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:69 +msgid "Profile →" +msgstr "Profil →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:64 +msgid "View other subscriptions →" +msgstr "Afficher les autres abonnements →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:52 +msgid "General" +msgstr "Général" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:102 +msgctxt "relation to order" +msgid "Unknown Order Type" +msgstr "Type de commande inconnu" + +#: includes/admin/class-wcs-wc-admin-manager.php:59 +msgid "Edit Subscription" +msgstr "Modifier l’abonnement" + +#: includes/admin/class-wcs-wc-admin-manager.php:49 +msgid "Add New" +msgstr "Ajouter" + +#: includes/admin/class-wcs-admin-meta-boxes.php:284 +msgid "Retry renewal payment action requested by admin." +msgstr "" +"Réessayez l’action de paiement de renouvellement demandée par " +"l’administrateur." + +#. translators: Placeholders are opening and closing link tags. +#: includes/admin/class-wc-subscriptions-admin.php:1541 +msgid "" +"We weren't able to locate the set of report results you requested. Please " +"regenerate the link from the %1$sSubscription Reports screen%2$s." +msgstr "" +"Nous n’avons pas pu localiser l’ensemble de résultats de rapport que vous " +"avez demandé. Veuillez régénérer le lien sur l’%1$sécran Rapports " +"d’abonnement%2$s." + +#: wcs-functions.php:130 +msgctxt "Error message while creating a subscription" +msgid "" +"Invalid created date. The date must be a string and of the format: \"Y-m-d H:" +"i:s\"." +msgstr "" + +#: templates/checkout/form-change-payment-method.php:49 +msgctxt "text on button on checkout page" +msgid "Add payment method" +msgstr "" + +#. translators: placeholder is a localized date and time (e.g. "February 1, +#. 2018 10:20 PM") +#: includes/wcs-formatting-functions.php:251 +msgctxt "wcs_get_human_time_diff" +msgid "%s" +msgstr "" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:80 +msgctxt "plugin version number used in admin notice" +msgid "3.0" +msgstr "" + +#: includes/class-wcs-retry-manager.php:268 +msgctxt "used in order note as reason for why status changed" +msgid "Retry rule reapplied:" +msgstr "" + +#. translators: 1: previous token, 2: new token. +#: includes/class-wcs-my-account-payment-methods.php:199 +msgctxt "used in subscription note" +msgid "" +"Payment method meta updated after customer changed their default token and " +"opted to update their subscriptions. Payment meta changed from %1$s to %2$s" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:234 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (charge the full recurring amount at sign-up)" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:233 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (do not charge any recurring amount)" +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:150 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:198 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Customer requested to renew early:" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:711 +#: includes/class-wc-subscriptions-change-payment-gateway.php:752 +msgctxt "the page title of the add payment method form" +msgid "Add payment method" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:279 +msgctxt "label on button, imperative" +msgid "Add payment" +msgstr "" + +#. translators: %s: address type (eg. 'billing' or 'shipping'). +#: includes/class-wc-subscriptions-addresses.php:213 +msgctxt "change billing or shipping address" +msgid "Change %s address" +msgstr "" + +#. translators: %s: parent order number (linked to its details screen). +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:387 +msgctxt "subscription note after linking to a parent order" +msgid "Subscription linked to parent order %s via admin." +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribe Order" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:204 +msgctxt "label for the system status page" +msgid "Retries Migration Status" +msgstr "État des nouvelles tentatives de migration" + +#: includes/payment-retry/class-wcs-retry-admin.php:196 +msgctxt "label for the system status page" +msgid "Custom Retry Rule" +msgstr "Règle de nouvelle tentative personnalisée" + +#: includes/payment-retry/class-wcs-retry-admin.php:188 +msgctxt "label for the system status page" +msgid "Custom Raw Retry Rule" +msgstr "Règle de nouvelle tentative brute personnalisée" + +#: includes/payment-retry/class-wcs-retry-admin.php:180 +msgctxt "label for the system status page" +msgid "Custom Retry Rule Class" +msgstr "Classe de règle de nouvelle tentative personnalisée" + +#: includes/payment-retry/class-wcs-retry-admin.php:172 +msgctxt "label for the system status page" +msgid "Custom Retry Rules" +msgstr "Règles de nouvelle tentative personnalisées" + +#: includes/admin/class-wcs-admin-system-status.php:357 +msgctxt "label for the system status page" +msgid "Country / State" +msgstr "Pays / État" + +#: includes/admin/class-wcs-admin-system-status.php:329 +msgctxt "label for the system status page" +msgid "PayPal Reference Transactions Enabled" +msgstr "PayPal Reference Transactions activé" + +#: includes/admin/class-wcs-admin-system-status.php:295 +msgctxt "label for the system status page" +msgid "Other" +msgstr "Autre" + +#: includes/admin/class-wcs-admin-system-status.php:265 +msgctxt "label for the system status page" +msgid "Active Product Key" +msgstr "Clé de produit active" + +#: includes/admin/class-wcs-admin-system-status.php:242 +msgctxt "label for the system status page" +msgid "WooCommerce Account Connected" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:221 +msgctxt "label for the system status page" +msgid "Subscription Statuses" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:119 +msgctxt "Live URL, Label on WooCommerce -> System Status page" +msgid "Subscriptions Live URL" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:75 +msgctxt "meta box title" +msgid "Schedule" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:243 +msgctxt "there's a number immediately in front of this text" +msgid "days prior to Renewal Day" +msgstr "" + +#. Author URI of the plugin +msgid "https://woocommerce.com/" +msgstr "https://woocommerce.com/" + +#. translators: 1$-2$: opening and closing tags. 3$-4$: opening and +#. closing link tags for learn more. Leads to duplicate site article on docs. +#. 5$-6$: Opening and closing link to production URL. 7$: Production URL . +#: woocommerce-subscriptions.php:930 +msgid "" +"It looks like this site has moved or is a duplicate site. %1$sWooCommerce " +"Subscriptions%2$s has disabled automatic payments and subscription related " +"emails on this site to prevent duplicate payments from a staging or test " +"environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be " +"the site's URL. %3$sLearn more »%4$s." +msgstr "" +"Il semble que ce site a été déplacé ou est un site dupliqué. %1$sWooCommerce " +"Subscriptions%2$s a désactivé des paiements automatiques et les e-mails liés " +"aux abonnements sur ce site pour éviter les paiements en double à partir " +"d’un environnement de préproduction ou de test. %1$sWooCommerce " +"Subscriptions%2$s pense que %5$s%7$s%6$s est l’URL du site. %3$sEn savoir " +"plus »%4$s." + +#: woocommerce-subscriptions.php:861 +msgid "Installed Plugins" +msgstr "Extensions installées" + +#. translators: 1-2: opening/closing tags, 3: Subscriptions version. +#: woocommerce-subscriptions.php:858 +msgid "" +"%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early " +"Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce " +"Subscriptions%2$s comes with that plugin's functionality packaged into the " +"core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to " +"avoid any conflicts." +msgstr "" +"%1$sAttention !%2$sNous pouvons voir que l’extension %1$sWooCommerce " +"Subscriptions Early Renewal%2$s est active. La version %3$s de " +"%1$sWooCommerce Subscriptions%2$s est fournie avec la fonctionnalité de " +"cette extension intégrée à l’extension principale. Veuillez désactiver " +"WooCommerce Subscriptions Early Renewal pour éviter tout conflit." + +#: woocommerce-subscriptions.php:393 +msgid "Would you like to add a payment method now?" +msgstr "Voulez-vous ajouter un moyen de paiement maintenant ?" + +#: woocommerce-subscriptions.php:393 +msgid "" +"To enable automatic renewals for this subscription, you will first need to " +"add a payment method." +msgstr "" +"Pour activer les renouvellements automatiques pour cet abonnement, vous " +"devez d’abord ajouter un moyen de paiement." + +#: templates/single-product/add-to-cart/variable-subscription.php:34 +msgid "You have added a variation of this product to the cart already." +msgstr "Vous avez déjà ajouté une variante de ce produit au panier." + +#: templates/myaccount/subscription-details.php:71 +msgid "Payment" +msgstr "Paiement" + +#: templates/myaccount/subscription-details.php:57 +msgid "Disable auto renew" +msgstr "Désactiver le renouvellement automatique" + +#: templates/myaccount/subscription-details.php:50 +msgid "Enable auto renew" +msgstr "Activer le renouvellement automatique" + +#: templates/myaccount/subscription-details.php:42 +msgid "Auto renew" +msgstr "Renouvellement automatique" + +#: templates/myaccount/my-subscriptions.php:72 +msgid "You have reached the end of subscriptions. Go to the %sfirst page%s." +msgstr "" +"Vous avez atteint la fin des abonnements. Allez à la %spremière page%s." + +#: templates/myaccount/my-subscriptions.php:65 +msgid "Next" +msgstr "Suivant" + +#: templates/myaccount/my-subscriptions.php:61 +msgid "Previous" +msgstr "Précédent" + +#. translators: $1: opening tag, $2: closing tag +#: templates/checkout/form-change-payment-method.php:91 +msgid "" +"Update the payment method used for %1$sall%2$s of my current subscriptions" +msgstr "" +"Mettre à jour le moyen de paiement utilisé pour %1$stous%2$s mes abonnements " +"actuels" + +#. translators: $1 the log file name $2 and $3 are opening and closing link +#. tags, respectively. +#: templates/admin/html-failed-scheduled-action-notice.php:38 +msgid "" +"To see further details about these errors, view the %1$s log file from the " +"%2$sWooCommerce logs screen.%2$s" +msgstr "" +"Pour voir plus de détails sur ces erreurs, consultez le fichier journal %1$s " +"sur l’%2$sécran des journaux de WooCommerce.%2$s" + +#: templates/admin/html-failed-scheduled-action-notice.php:31 +msgid "Affected event:" +msgid_plural "Affected events:" +msgstr[0] "Événement affecté :" +msgstr[1] "Événements affectés :" + +#: templates/admin/html-failed-scheduled-action-notice.php:21 +msgid "" +"An error has occurred while processing a recent subscription related event. " +"For steps on how to fix the affected subscription and to learn more about " +"the possible causes of this error, please read our guide %1$shere%2$s." +msgid_plural "" +"An error has occurred while processing recent subscription related events. " +"For steps on how to fix the affected subscriptions and to learn more about " +"the possible causes of this error, please read our guide %1$shere%2$s." +msgstr[0] "" +"Une erreur est survenue lors du traitement d’un événement récent lié à un " +"abonnement. Pour savoir comment résoudre l’abonnement affecté et en savoir " +"plus sur les causes possibles de cette erreur, veuillez lire notre guide " +"%1$sici%2$s." +msgstr[1] "" +"Une erreur est survenue lors du traitement d’événements récents liés à un " +"abonnement. Pour savoir comment résoudre les abonnements affectés et en " +"savoir plus sur les causes possibles de cette erreur, veuillez lire notre " +"guide %1$sici%2$s." + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/wcs-formatting-functions.php:243 +msgid "in %s" +msgstr "dans %s" + +#: includes/wcs-cart-functions.php:252 +msgid "[Remove]" +msgstr "[Enlever]" + +#: includes/upgrades/templates/update-welcome-notice.php:8 +msgid "What's new?" +msgstr "Qu’est-ce qui change ?" + +#. translators: placeholder $1 is the Subscription version string ('2.3'), $2-3 +#. are opening and closing tags +#: includes/upgrades/templates/update-welcome-notice.php:5 +msgid "" +"Version %1$s brings some new improvements requested by store managers just " +"like you (and possibly even by %2$syou%3$s)." +msgstr "" +"La version %1$s apporte de nouvelles améliorations demandées par des gérants " +"de boutique comme vous (et peut-être même par %2$svous%3$s)." + +#: includes/upgrades/class-wcs-repair-suspended-paypal-subscriptions.php:51 +msgid "" +"Subscription suspended by Database repair script. This subscription was " +"suspended via PayPal." +msgstr "" +"Abonnement suspendu par le script de réparation de base de données. Cet " +"abonnement a été suspendu via PayPal." + +#. translators: 1-2: opening/closing tags, 3-4: opening/closing tags +#. linked to ticket form. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:895 +msgid "" +"%1$sWarning!%2$s We discovered an issue in %1$sWooCommerce Subscriptions 2.3." +"0 - 2.3.2%2$s that may cause your subscription renewal order and customer " +"subscription caches to contain invalid data. For information about how to " +"update the cached data, please %3$sopen a new support ticket%4$s." +msgstr "" +"%1$sAttention !%2$s Nous avons découvert un problème dans %1$sWooCommerce " +"Subscriptions 2.3.0 - 2.3.2%2$s qui peut entraîner la présence de données " +"non valides dans votre commande de renouvellement d’abonnement et les caches " +"d’abonnements client. Pour plus d’informations sur la mise à jour des " +"données mises en cache, veuillez %3$souvrir un nouveau ticket " +"d’assistance%4$s." + +#. translators: 1-2: opening/closing tags, 3: active version of +#. Subscriptions, 4: current version of Subscriptions, 5-6: opening/closing +#. tags linked to ticket form, 7-8: opening/closing tags linked to +#. documentation. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:822 +msgid "" +"%1$sWarning!%2$s It appears that you have downgraded %1$sWooCommerce " +"Subscriptions%2$s from %3$s to %4$s. Downgrading the plugin in this way may " +"cause issues. Please update to %3$s or higher, or %5$sopen a new support " +"ticket%6$s for further assistance. %7$sLearn more »%8$s" +msgstr "" +"%1$sAttention !%2$s Il semble que vous avez rétrogradé %1$sWooCommerce " +"Subscriptions%2$s de %3$s à %4$s. Rétrograder l’extension de cette manière " +"peut causer des problèmes. Veuillez mettre à jour vers %3$s ou supérieur ou " +"bien %5$souvrir un nouveau ticket d’assistance%6$s pour obtenir une " +"assistance supplémentaire. %7$sEn savoir plus »%8$s" + +#: includes/privacy/class-wcs-privacy.php:277 +msgid "Customers with a subscription are excluded from this setting." +msgstr "Les clients avec un abonnement sont exclus de ce paramètre." + +#: includes/privacy/class-wcs-privacy.php:233 +msgid "" +"Retain ended subscriptions and their related orders for a specified duration " +"before anonymizing the personal data within them." +msgstr "" +"Conservez les abonnements terminés et leurs commandes liées pour la durée " +"spécifiée avant l’anonymisation des données personnelles." + +#: includes/privacy/class-wcs-privacy.php:232 +msgid "Retain ended subscriptions" +msgstr "Conserver les abonnements terminés" + +#. Translators: %s URL to erasure request screen. +#: includes/privacy/class-wcs-privacy.php:223 +msgid "" +"When handling an %s, should personal data within subscriptions be retained " +"or removed?" +msgstr "" +"Lors du traitement d’une %s, les données personnelles dans les abonnements " +"doivent-elles être conservées ou supprimées ?" + +#: includes/privacy/class-wcs-privacy.php:221 +msgid "Remove personal data from subscriptions" +msgstr "Supprimer les données personnelles des abonnements" + +#: includes/privacy/class-wcs-privacy.php:215 +msgid "account erasure request" +msgstr "demande d’effacement de données" + +#. translators: placeholders are opening and closing tags. +#: includes/privacy/class-wcs-privacy.php:195 +msgid "" +"%1$sNote:%2$s Orders which are related to subscriptions will not be included " +"in the orders affected by these settings." +msgstr "" +"%1$sRemarque :%2$s les commandes liées à des abonnements ne seront pas " +"incluses dans les commandes affectées par ces paramètres." + +#. translators: %d: number of subscriptions affected. +#: includes/privacy/class-wcs-privacy.php:176 +msgid "Removed personal data from %d subscription." +msgid_plural "Removed personal data from %d subscriptions." +msgstr[0] "Données personnelles supprimées de %d abonnement." +msgstr[1] "Données personnelles supprimées de %d abonnements." + +#: includes/privacy/class-wcs-privacy.php:109 +msgid "Cancel and remove personal data" +msgstr "Annuler et supprimer les données personnelles" + +#. translators: placeholders are opening and closing link tags, linking to +#. additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:99 +msgid "" +"If you are using PayPal Standard or PayPal Reference transactions please see " +"the %1$sPayPal Privacy Policy%2$s for more details." +msgstr "" +"Si vous utilisez PayPal Standard ou PayPal Reference Transactions, veuillez " +"consulter la %1$sPolitique de confidentialité de PayPal%2$s pour plus de " +"détails." + +#: includes/privacy/class-wcs-privacy.php:97 +msgid "" +"What personal information your store shares with external sources depends on " +"which third-party payment processor plugins you are using to collect " +"subscription payments. We recommend that you consult with their privacy " +"policies to inform this section of your privacy policy." +msgstr "" +"Les informations personnelles que votre boutique partage avec des sources " +"externes dépendent des extensions de plateforme de paiement tierces que vous " +"utilisez pour collecter les paiements d’abonnement. Nous vous recommandons " +"de consulter leurs politiques de confidentialité pour informer cette section " +"de votre politique de confidentialité." + +#: includes/privacy/class-wcs-privacy.php:96 +msgid "What we share with others" +msgstr "Ce que nous partageons avec d’autres" + +#. translators: placeholders are opening and closing link tags, linking to +#. additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:95 +msgid "" +"For the purposes of processing recurring subscription payments, we store the " +"customer's name, billing address, shipping address, email address, phone " +"number and credit card/payment details." +msgstr "" +"À des fins de traitement des paiements d’abonnement récurrents, nous " +"stockons le nom du client, son adresse de facturation, son adresse de " +"livraison, son adresse e-mail, son numéro de téléphone et ses détails de " +"carte de crédit/paiement." + +#. translators: placeholders are opening and closing link tags, linking to +#. additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:94 +msgid "What we collect and store" +msgstr "Ce que nous collectons et stockons" + +#: includes/privacy/class-wcs-privacy.php:92 +msgid "" +"By using WooCommerce Subscriptions, you may be storing personal data and " +"depending on which third-party payment processors you’re using to take " +"subscription payments, you may be sharing personal data with external " +"sources." +msgstr "" +"En utilisant WooCommerce Subscriptions, il est possible que vous stockiez " +"des données personnelles et, en fonction des plateformes de paiement tierces " +"que vous utilisez pour accepter les paiements d’abonnement, il est possible " +"que vous partagiez des données personnelles avec des sources externes." + +#: includes/privacy/class-wcs-privacy.php:43 +#: includes/privacy/class-wcs-privacy.php:44 +msgid "Subscriptions Data" +msgstr "Données des abonnements" + +#: includes/privacy/class-wcs-privacy-exporters.php:86 +msgid "Email Address" +msgstr "Adresse e-mail" + +#: includes/privacy/class-wcs-privacy-exporters.php:85 +msgid "Phone Number" +msgstr "Numéro de téléphone" + +#: includes/privacy/class-wcs-privacy-exporters.php:82 +msgid "Browser User Agent" +msgstr "Agent utilisateur du navigateur" + +#: includes/privacy/class-wcs-privacy-exporters.php:81 +msgid "IP Address" +msgstr "Addresse IP" + +#: includes/privacy/class-wcs-privacy-exporters.php:80 +msgid "Subscription Items" +msgstr "Articles d’abonnement" + +#: includes/privacy/class-wcs-privacy-exporters.php:78 +msgid "Created Date" +msgstr "Date de création" + +#: includes/privacy/class-wcs-privacy-erasers.php:189 +msgid "Personal data removed." +msgstr "Données personnelles supprimées." + +#. Translators: %s subscription number. +#: includes/privacy/class-wcs-privacy-erasers.php:75 +msgid "Personal data within subscription %s has been retained." +msgstr "Les données personnelles de l’abonnement %s ont été conservées." + +#. Translators: %s subscription number. +#: includes/privacy/class-wcs-privacy-erasers.php:71 +msgid "Removed personal data from subscription %s." +msgstr "Données personnelles supprimées de l’abonnement %s." + +#. translators: $1 is the log file name. $2 and $3 are opening and closing link +#. tags, respectively. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:46 +msgid "" +"To see the full error, view the %1$s log file from the %2$sWooCommerce logs " +"screen.%3$s." +msgstr "" +"Pour voir l’erreur complète, consultez le fichier journal %1$s sur " +"l’%2$sécran des journaux de WooCommerce%3$s." + +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:36 +msgid "Last recorded error:" +msgstr "Dernière erreur enregistrée :" + +#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:18 +msgid "" +"A fatal error has occurred while processing a recent subscription payment " +"with PayPal. Please %1$sopen a new ticket at WooCommerce Support%3$s " +"immediately to get this resolved. %2$sLearn more »%3$s" +msgstr "" +"Une erreur fatale est survenue lors du traitement d’un paiement d’abonnement " +"récent avec PayPal. Veuillez immédiatement %1$souvrir un nouveau ticket sur " +"WooCommerce Support%3$s pour résoudre cette erreur. %2$sEn savoir plus " +"»%3$s" + +#. translators: Placeholders are the opening and closing link tags. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:320 +msgid "" +"Before enabling PayPal Standard for Subscriptions, please note, when using " +"PayPal Standard, customers are locked into using PayPal Standard for the " +"life of their subscription, and PayPal Standard has a number of limitations. " +"Please read the guide on %1$swhy we don't recommend PayPal Standard%2$s for " +"Subscriptions before choosing to enable this option." +msgstr "" +"Avant d’activer PayPal Standard pour Subscriptions, veuillez noter que, " +"lorsque PayPal Standard est utilisé, les clients sont obligés d’utiliser " +"PayPal Standard pendant toute la durée de leur abonnement, et PayPal " +"Standard présente un certain nombre de limites. Veuillez lire le guide sur " +"%1$sla raison pour laquelle nous ne recommandons pas PayPal Standard%2$s " +"pour Subscriptions avant de choisir d’activer cette option." + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:312 +msgid "Enable PayPal Standard for Subscriptions" +msgstr "Activer PayPal Standard pour Subscriptions" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:199 +msgid "Open a ticket" +msgstr "Ouvrir un ticket" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:279 +msgid "Change payment features:" +msgstr "Modifier des fonctionnalités de paiement :" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:275 +msgid "Subscription features:" +msgstr "Fonctionnalités d’abonnement :" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:272 +msgid "Supported features:" +msgstr "Fonctionnalités prises en charge :" + +#. translators: %s: default e-mail heading. +#: includes/emails/class-wcs-email-cancelled-subscription.php:168 +msgid "" +"This controls the main heading contained within the email notification. " +"Leave blank to use the default heading: %s." +msgstr "" +"Cela contrôle l’en-tête principal contenu dans la notification par e-mail. " +"Laisser vide pour utiliser l’en-tête par défaut : %s." + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:55 +msgid "" +"With early renewals enabled, customers can renew their subscriptions before " +"the next payment date." +msgstr "" +"Lorsque les renouvellements anticipés sont activés, les clients peuvent " +"renouveler leurs abonnements avant la date du prochain paiement." + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:54 +msgid "Accept Early Renewal Payments" +msgstr "Accepter les paiements de renouvellement anticipé" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:53 +msgid "Early Renewal" +msgstr "Renouvellement anticipé" + +#. translators: %s: order ID (linked to details page). +#: includes/early-renewal/class-wcs-cart-early-renewal.php:312 +msgid "Order %s created to record early renewal." +msgstr "Commande %s créée pour enregistrer le renouvellement anticipé." + +#. translators: placeholder contains a link to the order's edit screen. +#: includes/early-renewal/wcs-early-renewal-functions.php:172 +msgid "" +"Failed to update subscription dates after customer renewed early with order " +"%s." +msgstr "" +"Échec de la mise à jour des dates d’abonnement après le renouvellement " +"anticipé du client avec la commande %s." + +#. translators: placeholder contains a link to the order's edit screen. +#: includes/early-renewal/wcs-early-renewal-functions.php:169 +msgid "Customer successfully renewed early with order %s." +msgstr "Le client a réussi le renouvellement anticipé avec la commande %s." + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:105 +msgid "Complete checkout to renew now." +msgstr "Terminez la validation de commande pour renouveler maintenant." + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:99 +msgid "" +"You can not renew this subscription early. Please contact us if you need " +"assistance." +msgstr "" +"Vous ne pouvez pas renouveler cet abonnement de manière anticipée. Contactez-" +"nous si vous avez besoin d’aide." + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:71 +msgid "Renew now" +msgstr "Renouveler maintenant" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "" +"This will clear the persistent cache of all renewal, switch, resubscribe and " +"other order types for all subscriptions in your store. Expect slower " +"performance of checkout, renewal and other subscription related functions " +"after taking this action. The caches will be regenerated overtime as related " +"order queries are run." +msgstr "" +"Cela effacera le cache persistant des commandes de renouvellement, de " +"changement, de réabonnement etc. pour tous les abonnements dans votre " +"boutique. Attendez-vous à une performance plus lente de la validation de " +"commande, du renouvellement et des autres fonctions liées à l’abonnement " +"après avoir effectué cette action. Les caches sont régénérés au fur et à " +"mesure que les requêtes de commande liées sont exécutées." + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "Delete Related Order Cache" +msgstr "Supprimer le cache de commandes liées" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "" +"This will generate the persistent cache of all renewal, switch, resubscribe " +"and other order types for all subscriptions in your store. The caches will " +"be generated overtime in the background (via Action Scheduler)." +msgstr "" +"Cela générera le cache persistant des commandes de renouvellement, de " +"changement, de réabonnement etc. pour tous les abonnements dans votre " +"boutique. Les caches sont générés au fur et à mesure en arrière-plan (via le " +"Planificateur d’actions)." + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "Generate Related Order Cache" +msgstr "Générer le cache de commandes liées" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:55 +msgid "" +"This will clear the persistent cache of all of subscriptions stored against " +"users in your store. Expect slower performance of checkout, renewal and " +"other subscription related functions after taking this action. The caches " +"will be regenerated overtime as queries to find a given user's subscriptions " +"are run." +msgstr "" +"Cela effacera le cache persistant de tous les abonnements stockés avec les " +"utilisateurs dans votre boutique. Attendez-vous à une performance plus lente " +"de la validation de commande, du renouvellement et des autres fonctions " +"liées à l’abonnement après avoir effectué cette action. Les caches sont " +"régénérés au fur et à mesure que les requêtes pour trouver les abonnements " +"d’un utilisateur donné sont exécutées." + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:55 +msgid "Delete Customer Subscription Cache" +msgstr "Supprimer le cache d’abonnement client" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:54 +msgid "" +"This will generate the persistent cache for linking users with subscriptions." +" The caches will be generated overtime in the background (via Action " +"Scheduler)." +msgstr "" +"Cela générera le cache persistant pour lier les utilisateurs avec des " +"abonnements. Les caches sont générés au fur et à mesure en arrière-plan (via " +"le Planificateur d’actions)." + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:54 +msgid "Generate Customer Subscription Cache" +msgstr "Générer le cache d’abonnement client" + +#: includes/class-wcs-staging.php:55 +msgid "staging" +msgstr "préproduction" + +#. translators: 1-2: opening/closing tags - linked to staging site, 3: link +#. to live site. +#: includes/class-wcs-staging.php:40 +msgid "" +"Payment processing skipped - renewal order created on %1$sstaging site%2$s " +"under staging site lock. Live site is at %3$s" +msgstr "" +"Traitement du paiement ignoré - commande de renouvellement créée sur le " +"%1$ssite de préproduction%2$s sous verrouillage du site de préproduction. Le " +"site en direct se trouve sur %3$s" + +#: includes/class-wcs-retry-manager.php:344 +msgid "" +"Payment retry attempted on renewal order with multiple related subscriptions " +"with no payment method in common." +msgstr "" +"Nouvelle tentative de paiement sur une commande de renouvellement avec " +"plusieurs abonnements liés sans moyen de paiement en commun." + +#: includes/class-wcs-query.php:306 +msgid "" +"Endpoint for the My Account → Change Subscription Payment Method page" +msgstr "" +"Point de terminaison pour la page Mon compte → Modifier le moyen de " +"paiement d’abonnement" + +#: includes/class-wcs-query.php:305 +msgid "Subscription payment method" +msgstr "Moyen de paiement d’abonnement" + +#. translators: placeholder is a page number. +#: includes/class-wcs-query.php:106 +msgid "Subscriptions (page %d)" +msgstr "Abonnements (page %d)" + +#. translators: %s: invalid type of update argument. +#: includes/class-wcs-post-meta-cache-manager.php:199 +msgid "" +"Invalid update type: %s. Post update types supported are \"add\" or " +"\"delete\". Updates are done on post meta directly." +msgstr "" +"Type de mise à jour non valide : %s. Les types de mise à jour d’article sont " +"« ajouter » ou « supprimer ». Les mises à jour sont effectuées sur les " +"métadonnées d’article directement." + +#. translators: 1$-2$: opening and closing tags. +#: includes/class-wcs-permalink-manager.php:91 +msgid "" +"Error saving Subscriptions endpoints: %1$sSubscriptions%2$s, %1$sView " +"subscription%2$s and %1$sSubscription payment method%2$s cannot be the same. " +"The changes have been reverted." +msgstr "" +"Erreur lors de l’enregistrement des points de terminaisons des abonnements : " +"%1$sAbonnements%2$s, %1$sAfficher l’abonnement%2$s et %1$sMoyen de paiement " +"d’abonnement%2$s ne peuvent pas être identiques. Les modifications ont été " +"annulées." + +#. translators: 1: token display name, 2: opening link tag, 4: closing link +#. tag, 3: opening link tag. +#: includes/class-wcs-my-account-payment-methods.php:158 +msgid "" +"Would you like to update your subscriptions to use this new payment method - " +"%1$s?%2$sYes%4$s | %3$sNo%4$s" +msgstr "" +"Voulez-vous mettre à jour vos abonnements pour utiliser ce nouveau moyen de " +"paiement - %1$s ?%2$sOui%4$s | %3$sNon%4$s" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:155 +msgid "" +"Allow customers to turn on and off automatic renewals from their View " +"Subscription page." +msgstr "" +"Autorisez les clients à activer et désactiver les renouvellements " +"automatiques sur leur page Afficher l’abonnement." + +#: includes/class-wcs-my-account-auto-renew-toggle.php:154 +msgid "Display the auto renewal toggle" +msgstr "Afficher la bascule de renouvellement automatique" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:153 +msgid "Auto Renewal Toggle" +msgstr "Bascule de renouvellement automatique" + +#: includes/class-wcs-failed-scheduled-action-manager.php:163 +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:106 +msgid "Learn more" +msgstr "En savoir plus" + +#: includes/class-wcs-failed-scheduled-action-manager.php:158 +msgid "Ignore this error" +msgstr "Ignorer cette erreur" + +#: includes/class-wcs-cart-renewal.php:210 +msgid "" +"This order can no longer be paid because the corresponding subscription does " +"not require payment at this time." +msgstr "" +"Cette commande ne peut plus être payée car l’abonnement correspondant ne " +"nécessite pas de paiement pour le moment." + +#: includes/class-wcs-cached-data-manager.php:127 +msgid "new related order methods in WCS_Related_Order_Store" +msgstr "nouvelles méthodes de commande liée dans WCS_Related_Order_Store" + +#: includes/class-wcs-cached-data-manager.php:110 +#: includes/class-wcs-cached-data-manager.php:240 +msgid "Customer subscription caching is now handled by %1$s and %2$s." +msgstr "" +"La mise en cache d’abonnement client est maintenant gérée par %1$s et %2$s." + +#: includes/class-wcs-cached-data-manager.php:86 +msgid "Customer subscription caching is now handled by %1$s." +msgstr "La mise en cache d’abonnement client est maintenant gérée par %1$s." + +#: includes/class-wcs-cached-data-manager.php:79 +msgid "Related order caching is now handled by %1$s." +msgstr "La mise en cache de commande liée est maintenant gérée par %1$s." + +#: includes/class-wc-subscriptions-synchroniser.php:247 +msgid "" +"Subscriptions created within this many days prior to the Renewal Day will " +"not be charged at sign-up. Set to zero for all new Subscriptions to be " +"charged the full recurring amount. Must be a positive number." +msgstr "" +"Les abonnements créés avant la date de renouvellement ne seront pas facturés " +"lors de l’inscription. Définissez sur zéro pour que tous les nouveaux " +"abonnements soient facturés du montant récurrent complet. Doit être un " +"nombre positif." + +#: includes/class-wc-subscriptions-synchroniser.php:242 +msgid "Sign-up grace period" +msgstr "Période de grâce d’inscription" + +#: includes/class-wc-subscriptions-synchroniser.php:226 +msgid "Prorate First Renewal" +msgstr "Premier renouvellement au prorata" + +#. translators: placeholder is a switch type. +#: includes/class-wcs-switch-cart-item.php:309 +msgid "" +"Invalid switch type \"%s\". Switch must be one of: \"upgrade\", " +"\"downgrade\" or \"crossgrade\"." +msgstr "" +"Type de changement non valide « %s ». Le changement doit être : « mise à " +"niveau », « rétrogradation » ou « reclassement »." + +#: includes/class-wc-subscriptions-product.php:969 +msgid "" +"This variation can not be removed because it is associated with active " +"subscriptions. To remove this variation, please cancel and delete the " +"subscriptions for it." +msgstr "" +"Cette variante ne peut pas être supprimée car elle est associée à des " +"abonnements actifs. Pour supprimer cette variante, veuillez annuler et " +"supprimer les abonnements correspondants." + +#. translators: %1$s refers to the price. This string is meant to prefix +#. another string below, e.g. "$5 now, and $5 on March 15th each year" +#: includes/class-wc-subscriptions-product.php:291 +msgid "%1$s now, and " +msgstr "%1$s maintenant, et" + +#: includes/class-wc-subscriptions-coupon.php:1086 +msgid "Active for unlimited payments" +msgstr "Actif pour les paiements illimités" + +#. translators: %d refers to the number of payments the coupon can be used for. +#: includes/class-wc-subscriptions-coupon.php:1082 +msgid "Active for %d payment" +msgid_plural "Active for %d payments" +msgstr[0] "Actif pour %d paiement" +msgstr[1] "Actif pour %d paiements" + +#: includes/class-wc-subscriptions-coupon.php:950 +msgid "" +"Coupon will be limited to the given number of payments. It will then be " +"automatically removed from the subscription. \"Payments\" also includes the " +"initial subscription payment." +msgstr "" +"Le code de promotion sera limité au nombre donné de paiements. Il sera " +"ensuite automatiquement supprimé de l’abonnement. « Paiements » inclut " +"également le paiement d’abonnement initial." + +#: includes/class-wc-subscriptions-coupon.php:949 +msgid "Unlimited payments" +msgstr "Paiements illimités" + +#: includes/class-wc-subscriptions-coupon.php:948 +msgid "Active for x payments" +msgstr "Actif pour x paiements" + +#: includes/class-wc-subscriptions-coupon.php:933 +msgid "" +"Sorry, it seems there are no available payment methods which support the " +"recurring coupon you are using. Please contact us if you require assistance " +"or wish to make alternate arrangements." +msgstr "" +"Désolé, il semble qu’aucun moyen de paiement ne soit disponible pour le code " +"de promotion récurrent que vous utilisez. Veuillez nous contacter si vous " +"avez besoin d’aide ou si vous désirez mettre en place une alternative." + +#: includes/class-wc-subscriptions-coupon.php:717 +msgid "Discount" +msgstr "Remise" + +#: includes/class-wc-subscriptions-coupon.php:697 +msgid "Initial payment discount" +msgstr "Remise sur le paiement initial" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:797 +msgid "" +"Please log in to your account below to choose a new payment method for your " +"subscription." +msgstr "" +"Veuillez vous connecter à votre compte ci-dessous pour choisir un nouveau " +"moyen de paiement pour votre abonnement." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:380 +#: includes/class-wc-subscriptions-change-payment-gateway.php:382 +msgid "Payment method updated for all your current subscriptions." +msgstr "Moyen de paiement mis à jour pour tous vos abonnements actuels." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:340 +msgid "Payment method added." +msgstr "Moyen de paiement ajouté." + +#: includes/class-wc-subscription.php:1900 +msgid "" +"The \"all\" value for $order_type parameter is deprecated. It was a misnomer," +" as it did not return resubscribe orders. It was also inconsistent with " +"order type values accepted by wcs_get_subscription_orders(). Use array( " +"\"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or " +"\"any\" to receive all order types, including switch and resubscribe." +msgstr "" +"La valeur « tous » du paramètre $order_type est obsolète. Elle était " +"inappropriée, car elle ne renvoyait pas les commandes de réabonnement. Elle " +"était également incohérente avec les valeurs de type de commande acceptées " +"par wcs_get_subscription_orders(). Utilisez un tableau (« parent », " +"« renouvellement », « changement ») pour conserver le comportement précédent " +"ou « n’importe lequel » pour recevoir tous les types de commande, notamment " +"changement et réabonnement." + +#: includes/class-wc-subscription.php:1757 +msgid "Payment status marked complete." +msgstr "État de paiement marqué comme terminé." + +#: includes/class-wc-subscription.php:1326 +msgid "The creation date of a subscription can not be deleted, only updated." +msgstr "" +"La date de création d’un abonnement ne peut pas être supprimée, uniquement " +"mise à jour." + +#: includes/class-wc-subscription.php:604 +msgid "Error during subscription status transition." +msgstr "Une erreur est survenue pendant le changement d’état de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:564 +msgid "The date the subscription's latest order was paid, in GMT." +msgstr "" +"Date à laquelle la dernière commande de l’abonnement a été payée, au format " +"GMT." + +#: includes/api/class-wc-rest-subscriptions-controller.php:558 +msgid "The date the subscription's latest order was completed, in GMT." +msgstr "" +"Date à laquelle la dernière commande de l’abonnement a été terminée, au " +"format GMT." + +#: includes/api/class-wc-rest-subscriptions-controller.php:552 +msgid "The subscription's resubscribed subscription ID." +msgstr "ID d’abonnement réabonné de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:546 +msgid "" +"The subscription's original subscription ID if this is a resubscribed " +"subscription." +msgstr "" +"ID d’abonnement original de l’abonnement s’il s’agit d’abonnement réabonné." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:855 +msgid "New Subscriptions" +msgstr "Nouveaux abonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:535 +msgid "" +"The number of subscriptions created during this period, either by being " +"manually created, imported or a customer placing an order. This includes " +"orders pending payment." +msgstr "" +"Nombre d’abonnements créés pendant cette période, soit créés manuellement, " +"soit importés, soit via la commande d’un client. Cela inclut les commandes " +"en attente de paiement." + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:20 +msgid "Product" +msgstr "Produit" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:50 +msgid "The average value of all customers' sign-up, switch and renewal orders." +msgstr "" +"Valeur moyenne de toutes les commandes d’inscription, de changement et de " +"renouvellement des clients." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:47 +msgid "" +"The total number of sign-up, switch and renewal orders placed with your " +"store with a paid status (i.e. processing or complete)." +msgstr "" +"Nombre total des commandes d’inscription, de changement et de renouvellement " +"placées avec votre boutique avec un état payé (c.-à-d. traitement ou terminé)" +"." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:46 +msgid "" +"The total number of subscriptions with a status other than pending or " +"trashed." +msgstr "" +"Nombre total d’abonnements avec un état autre que en attente ou déplacé vers " +"la corbeille." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:45 +msgid "" +"The total number of subscriptions with a status of active or pending " +"cancellation." +msgstr "" +"Nombre total d’abonnements avec un état d’annulation active ou en attente." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:44 +msgid "" +"The number of unique customers with a subscription of any status other than " +"pending or trashed." +msgstr "" +"Nombre de clients uniques avec un abonnement avec un état autre que en " +"attente ou déplacé vers la corbeille." + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, +#. respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:248 +msgid "%2$s%1$s cancellation%3$s subscription cancellations this month" +msgid_plural "%2$s%1$s cancellations%3$s subscription cancellations this month" +msgstr[0] "%2$s%1$s annulation%3$s annulations d’abonnement ce mois-ci" +msgstr[1] "%2$s%1$s annulations%3$s annulations d’abonnement ce mois-ci" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-dashboard.php:240 +msgid "%s renewal revenue this month" +msgstr "%s revenu de renouvellement ce mois-ci" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, +#. respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:232 +msgid "%2$s%1$s renewal%3$s subscription renewals this month" +msgid_plural "%2$s%1$s renewals%3$s subscription renewals this month" +msgstr[0] "%2$s%1$s renouvellement%3$s renouvellements d’abonnement ce mois-ci" +msgstr[1] "" +"%2$s%1$s renouvellements%3$s renouvellements d’abonnement ce mois-ci" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-dashboard.php:224 +msgid "%s signup revenue this month" +msgstr "%s revenu d’inscription ce mois-ci" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, +#. respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:216 +msgid "%2$s%1$s signup%3$s subscription signups this month" +msgid_plural "%2$s%1$s signups%3$s subscription signups this month" +msgstr[0] "%2$s%1$s inscription%3$s inscriptions d’abonnement ce mois-ci" +msgstr[1] "%2$s%1$s inscriptions%3$s inscriptions d’abonnement ce mois-ci" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:23 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:72 +msgid "Payment:" +msgstr "Paiement" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:214 +msgid "Customer add payment method page →" +msgstr "Page d’ajout de moyen de paiement du client →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:212 +msgid "Customer change payment method page →" +msgstr "Page de changement de moyen de paiement du client →" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:127 +msgid "Select an order…" +msgstr "Sélectionner une commande…" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:121 +msgid "Parent order:" +msgstr "Commande parente :" + +#. translators: placeholder is an order number. +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:114 +msgid "#%1$s" +msgstr "n°%1$s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:110 +msgid "Parent order: " +msgstr "Commande parente : " + +#: includes/admin/class-wcs-admin-system-status.php:72 +msgid "This section shows information about payment gateway feature support." +msgstr "" +"Cette section contient des informations sur la prise en charge de la " +"fonctionnalité de passerelle de paiement." + +#: includes/admin/class-wcs-admin-system-status.php:71 +msgid "Payment Gateway Support" +msgstr "Prise en charge de la passerelle de paiement" + +#: includes/admin/class-wcs-admin-system-status.php:67 +msgid "This section shows information about Subscription payment methods." +msgstr "" +"Cette section contient des informations sur les moyens de paiement " +"d’abonnement." + +#: includes/admin/class-wcs-admin-system-status.php:66 +msgid "Subscriptions by Payment Gateway" +msgstr "Abonnements par passerelle de paiement" + +#: includes/admin/class-wcs-admin-system-status.php:62 +msgid "This section shows general information about the store." +msgstr "Cette section contient des informations générales sur la boutique." + +#: includes/admin/class-wcs-admin-system-status.php:61 +msgid "Store Setup" +msgstr "Configuration de la boutique" + +#: includes/admin/class-wcs-admin-meta-boxes.php:253 +msgid "Create pending parent order requested by admin action." +msgstr "" +"Créez une commande parente en attente demandée par une action de " +"l’administrateur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:183 +msgid "Create pending parent order" +msgstr "Créer une commande parente en attente" + +#: includes/admin/class-wc-subscriptions-admin.php:2036 +msgid "Note that purchasing a subscription still requires an account." +msgstr "Notez que l’achat d’un abonnement nécessite toujours un compte." + +#: includes/admin/class-wc-subscriptions-admin.php:1595 +msgid "We can't find a paid subscription order for this user." +msgstr "" +"Nous ne trouvons pas de commande d’abonnement payée pour cet utilisateur." + +#: includes/admin/class-wc-subscriptions-admin.php:1344 +msgid "" +"Allow a subscription product with a $0 initial payment to be purchased " +"without providing a payment method. The customer will be required to provide " +"a payment method at the end of the initial period to keep the subscription " +"active." +msgstr "" +"Autorisez l’achat d’un produit d’abonnement avec un paiement initial de 0 $ " +"sans fournir de moyen de paiement. Le client devra fournir un moyen de " +"paiement à la fin de la période initiale pour maintenir l’abonnement actif." + +#: includes/admin/class-wc-subscriptions-admin.php:1340 +msgid "Allow $0 initial checkout without a payment method." +msgstr "" +"Autorisez une validation de commande initiale de 0 $ sans moyen de paiement." + +#: includes/admin/class-wc-subscriptions-admin.php:1339 +msgid "$0 Initial Checkout" +msgstr "Validation de commande initiale de 0 $" + +#: includes/admin/class-wc-subscriptions-admin.php:868 +msgid "" +"Because of this, it is not recommended as a payment method for Subscriptions " +"unless it is the only available option for your country." +msgstr "" +"Pour cette raison, il n’est pas recommandé comme moyen de paiement pour les " +"abonnements, sauf s’il s’agit de la seule option disponible pour votre pays." + +#: includes/admin/class-wc-subscriptions-admin.php:868 +msgid "" +"PayPal Standard has a number of limitations and does not support all " +"subscription features." +msgstr "" +"PayPal Standard présente un certain nombre de limites et ne prend pas en " +"charge toutes les fonctionnalités d’abonnement." + +#: includes/admin/class-wc-subscriptions-admin.php:2050 +msgid "" +"The product type can not be changed because this product is associated with " +"subscriptions." +msgstr "" +"Le type de produit ne peut pas être modifié car ce produit est associé à des " +"abonnements." + +#: includes/admin/class-wc-subscriptions-admin.php:836 +msgid "Delete all variations without a subscription" +msgstr "Supprimer toutes les variantes sans abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:447 +msgid "Subscription pricing" +msgstr "Tarifs d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:221 +msgid "Virtual" +msgstr "Virtuel" + +#: includes/admin/class-wc-subscriptions-admin.php:220 +msgid "Downloadable" +msgstr "Téléchargeable" + +#. translators: 1: relation type, 2: list of valid relation types. +#: includes/abstracts/abstract-wcs-related-order-store.php:148 +msgid "" +"Invalid relation type: %1$s. Order relationship type must be one of: %2$s." +msgstr "" +"Type de relation non valide : %1$s. Le type de relation de commande doit " +"être : %2$s." + +#: templates/emails/subscription-info.php:35 +msgctxt "subscription number in email table. (eg: #106)" +msgid "#%s" +msgstr "n°%s" + +#. translators: $1-$3: opening and closing tags $2: subscription's order +#. number +#: templates/emails/email-order-details.php:27 +msgctxt "Used in email notification" +msgid "Subscription %1$s#%2$s%3$s" +msgstr "Abonnement %1$sn°%2$s%3$s" + +#. translators: $1-$2: opening and closing tags $3: order's order number +#. $4: date of order in tags +#: includes/upgrades/templates/wcs-about.php:206 +msgid "" +"Subscriptions also now uses the renewal order to setup the cart for %smanual " +"renewals%s, making it easier to add products or discounts to a single " +"renewal paid manually." +msgstr "" +"Subscriptions utilise désormais la commande de renouvellement pour " +"configurer le panier pour les %srenouvellements manuels%s, ce qui facilite " +"l’ajout de produits ou de remises à un seul renouvellement payé manuellement." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:202 +msgid "" +"Subscriptions 2.1 now passes the renewal order's total, making it possible " +"to add a fee or discount to the renewal order with simple one-liners like " +"%s$order->add_fee()%s or %s$order->add_coupon()%s." +msgstr "" +"Subscriptions 2.1 transmet désormais le total de la commande de " +"renouvellement, ce qui permet d’ajouter des frais ou une remise à la " +"commande de renouvellement avec des mots simples comme %s$order->add_fee()%s " +"ou %s$order->add_coupon()%s." + +#: includes/upgrades/templates/wcs-about.php:199 +msgid "" +"In previous versions of Subscriptions, the subscription total was passed to " +"payment gateways as the amount to charge for automatic renewal payments. " +"This made it unnecessarily complicated to add one-time fees or discounts to " +"a renewal." +msgstr "" +"Dans les versions précédentes de Subscriptions, le total d’abonnement était " +"transmis aux passerelles de paiement comme montant à facturer pour les " +"paiements de renouvellement automatique. Cela compliquait inutilement " +"l’ajout de frais uniques ou de remises à un renouvellement." + +#. translators: placeholders are opening and closing code tags +#: includes/upgrades/templates/wcs-about.php:197 +msgid "Honour Renewal Order Data" +msgstr "Honorer les données de commande de renouvellement" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:187 +msgid "" +"Want the details of a specific subscription? Get %s/wp-" +"json/wc/v1/subscriptions//%s." +msgstr "" +"Vous voulez les détails d’un abonnement spécifique ? Obtenez %s/wp-" +"json/wc/v1/subscriptions//%s." + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:183 +msgid "" +"Want to list all the subscriptions on a site? Get %s/wp-" +"json/wc/v1/subscriptions%s." +msgstr "" +"Vous voulez répertorier tous les abonnements sur un site ? Obtenez %s/wp-" +"json/wc/v1/subscriptions%s." + +#: includes/upgrades/templates/wcs-about.php:180 +msgid "" +"Your applications can now create, read, update or delete subscriptions via " +"RESTful API endpoints with the same design as the latest version of " +"WooCommerce's REST API endpoints." +msgstr "" +"Vos applications peuvent désormais créer, lire, mettre à jour ou supprimer " +"des abonnements via des points de terminaison API RESTful avec la même " +"conception que la dernière version des points de terminaison API RESTful de " +"WooCommerce." + +#: includes/upgrades/templates/wcs-about.php:179 +msgid "" +"Subscriptions 2.1 adds support for subscription data to this infrastructure." +msgstr "" +"Subscriptions 2.1 ajoute la prise en charge des données d’abonnement à cette " +"infrastructure." + +#. translators: $1: opening tag linking to WC API docs, $2: closing +#. tag, $3: opening tag linking to WP API docs, $4: closing tag +#: includes/upgrades/templates/wcs-about.php:177 +msgid "" +"WooCommerce 2.6 added support for %1$sREST API%2$s endpoints built on " +"WordPress core's %3$sREST API%4$s infrastructure." +msgstr "" +"WooCommerce 2.6 a ajouté la prise en charge des points de terminaison " +"%1$sAPI REST%2$s créés sur l’infrastructure %3$sAPI REST%4$s du cÅ“ur de " +"WordPress." + +#: includes/upgrades/templates/wcs-about.php:174 +msgid "WP REST API Endpoints" +msgstr "Points de terminaison API REST WP" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:166 +msgid "" +"To apply a specific rule based on certain conditions, like high value orders " +"or an infrequent renewal schedule, you can use the retry specific " +"%s'wcs_get_retry_rule'%s filter. This provides the ID of the renewal order " +"for the failed payment, which can be used to find information about the " +"products, subscription and totals to which the failed payment relates." +msgstr "" +"Pour appliquer une règle spécifique basée sur certaines conditions, comme " +"des commandes de valeur élevée ou un calendrier de renouvellement peu " +"fréquent, vous pouvez utiliser le filtre %s'wcs_get_retry_rule'%s spécifique " +"aux nouvelles tentatives. Cela fournit l’ID de la commande de renouvellement " +"pour le paiement échoué, qui peut être utilisé pour trouver des informations " +"sur les produits, l’abonnement et les totaux auxquels le paiement échoué se " +"rapporte." + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about.php:162 +msgid "" +"With the %s'wcs_default_retry_rules'%s filter, you can define a set of " +"default rules to apply to all failed payments in your store." +msgstr "" +"Avec le filtre %s'wcs_default_retry_rules'%s, vous pouvez définir un " +"ensemble de règles par défaut à appliquer à tous les paiements échoués dans " +"votre boutique." + +#: includes/upgrades/templates/wcs-about.php:159 +msgid "" +"The best part about the new automatic retry system is that the retry rules " +"are completely customisable." +msgstr "" +"La meilleure partie du nouveau système de nouvelle tentative automatique est " +"que les règles de nouvelle tentative sont entièrement personnalisables." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:157 +msgid "Customise Retry Rules" +msgstr "Personnaliser des règles de nouvelle tentative" + +#: includes/upgrades/templates/wcs-about.php:139 +msgid "" +"With WooCommerce Subscribe All the Things, they can! This experimental " +"extension is exploring how to convert any product, including Product Bundles " +"and Composite Products, into a subscription product. It also offers " +"customers a way to subscribe to a cart of non-subscription products." +msgstr "" +"Avec WooCommerce Subscribe All the Things, ils le peuvent ! Cette extension " +"expérimentale explore comment convertir n’importe quel produit, dont des " +"groupes de produits et des produits composites, en un produit d’abonnement. " +"Elle permet aux clients de s’abonner à un panier de produits sans abonnement." + +#: includes/upgrades/templates/wcs-about.php:138 +msgid "" +"Want your customers to be able to subscribe to non-subscription products?" +msgstr "" +"Vous voulez que vos clients puissent s’abonner à des produits sans " +"abonnement ?" + +#: includes/upgrades/templates/wcs-about.php:137 +msgid "Subscribe All the Things" +msgstr "Subscribe All the Things" + +#: includes/upgrades/templates/wcs-about.php:128 +msgid "" +"This free extension makes it possible to migrate subscribers from 3rd party " +"systems to WooCommerce. It also makes it possible to export your " +"subscription data for analysis in spreadsheet tools or 3rd party apps." +msgstr "" +"Cette extension gratuite permet de migrer des abonnés de systèmes tiers vers " +"WooCommerce. Elle permet également d’exporter vos données d’abonnement pour " +"analyse dans des outils de feuille de calcul ou des applications tierces." + +#: includes/upgrades/templates/wcs-about.php:127 +msgid "" +"Import subscriptions to WooCommerce via CSV, or export your subscriptions " +"from WooCommerce to a CSV with the WooCommerce Subscriptions " +"Importer/Exporter extension." +msgstr "" +"Importez des abonnements vers WooCommerce via CSV ou exportez vos " +"abonnements depuis WooCommerce vers un fichier CSV avec l’extension " +"WooCommerce Subscriptions Importer/Exporter." + +#: includes/upgrades/templates/wcs-about.php:117 +msgid "" +"The Gifting extension makes it possible for one person to purchase a " +"subscription product for someone else. It then shares control of the " +"subscription between the purchaser and recipient, allowing both to manage " +"the subscription over its lifecycle." +msgstr "" +"L’extension Gifting permet à une personne d’acheter un produit d’abonnement " +"pour quelqu’un d’autre. Elle partage ensuite le contrôle de l’abonnement " +"entre l’acheteur et le destinataire, ce qui permet aux deux de gérer " +"l’abonnement tout au long de son cycle de vie." + +#: includes/upgrades/templates/wcs-about.php:116 +msgid "" +"What happens when a customer wants to purchase a subscription product for " +"someone else?" +msgstr "" +"Que se passe-t-il quand un client veut acheter un produit d’abonnement pour " +"quelqu’un d’autre ?" + +#: includes/upgrades/templates/wcs-about.php:109 +msgid "" +"That's not all we've working on for the last 12 months when it comes to " +"Subscriptions. We've also released mini-extensions to help you get the most " +"from your subscription store." +msgstr "" +"Ce n’est pas tout ce sur quoi nous travaillons depuis 12 mois en ce qui " +"concerne Subscriptions. Nous avons également publié des mini-extensions pour " +"vous aider à tirer le meilleur parti de votre boutique d’abonnement." + +#: includes/upgrades/templates/wcs-about.php:108 +msgid "But wait, there's more!" +msgstr "Attendez, vous avez encore tant à découvrir !" + +#: includes/upgrades/templates/wcs-about.php:99 +msgid "View Email Settings" +msgstr "Voir les paramètres d’e-mail" + +#: includes/upgrades/templates/wcs-about.php:97 +msgid "" +"These emails can be enabled, disabled and customised under the %sWooCommerce " +"> Settings > Emails%s administration screen." +msgstr "" +"Ces e-mails peuvent être activés, désactivés et personnalisés sur l’écran " +"d’administration %sWooCommerce > Réglages > E-mails%s." + +#: includes/upgrades/templates/wcs-about.php:95 +msgid "a subscription expires" +msgstr "un abonnement expire" + +#: includes/upgrades/templates/wcs-about.php:94 +msgid "an automatic payment fails" +msgstr "un paiement automatique échoue" + +#: includes/upgrades/templates/wcs-about.php:93 +msgid "a customer suspends a subscription" +msgstr "un client suspend un abonnement" + +#: includes/upgrades/templates/wcs-about.php:91 +msgid "" +"Subscriptions 2.1 also introduces a number of new emails to notify you when:" +msgstr "" +"Subscriptions 2.1 introduit également un certain nombre de nouveaux e-mails " +"pour vous informer quand :" + +#: includes/upgrades/templates/wcs-about.php:90 +msgid "New Subscription Emails" +msgstr "Nouveaux e-mails d’abonnement" + +#: includes/upgrades/templates/wcs-about.php:78 +msgid "Enable Automatic Retry" +msgstr "Activer la nouvelle tentative automatique" + +#: includes/upgrades/templates/wcs-about.php:76 +msgid "" +"The retry system is disabled by default. To enable it, visit the " +"Subscriptions settings administration screen." +msgstr "" +"Le système de nouvelle tentative est désactivé par défaut. Pour l’activer, " +"visitez l’écran d’administration de réglages des abonnements." + +#: includes/upgrades/templates/wcs-about.php:74 +msgid "the status applied to the renewal order and subscription" +msgstr "l’état appliqué à la commande de renouvellement et à l’abonnement" + +#: includes/upgrades/templates/wcs-about.php:73 +msgid "emails sent to the customer and store manager" +msgstr "les e-mails envoyés au client et au gérant de la boutique" + +#: includes/upgrades/templates/wcs-about.php:72 +msgid "how long to wait between retry attempts" +msgstr "la durée d’attente entre les nouvelles tentatives" + +#: includes/upgrades/templates/wcs-about.php:71 +msgid "the total number of retry attempts" +msgstr "le nombre total de nouvelles tentatives" + +#: includes/upgrades/templates/wcs-about.php:69 +msgid "" +"By default, Subscriptions will retry the payment 5 times over 7 days. The " +"rules that control the retry system can be modified to customise:" +msgstr "" +"Par défaut, Subscriptions tentera le paiement 5 fois pendant 7 jours. Les " +"règles qui contrôlent le système de nouvelle tentative peuvent être " +"modifiées pour personnaliser :" + +#: includes/upgrades/templates/wcs-about.php:68 +msgid "" +"Failed recurring payments can now be retried automatically. This helps " +"recover revenue that would otherwise be lost due to payment methods being " +"declined only temporarily." +msgstr "" +"Les paiements récurrents échoués peuvent maintenant être retentés " +"automatiquement. Cela permet de récupérer les revenus qui seraient autrement " +"perdus en raison du refus temporaire des moyens de paiement." + +#: includes/upgrades/templates/wcs-about.php:67 +msgid "Automatic Failed Payment Retry" +msgstr "Nouvelle tentative automatique de paiement échouée" + +#: includes/upgrades/templates/wcs-about.php:54 +msgid "View Reports" +msgstr "Voir les rapports" + +#: includes/upgrades/templates/wcs-about.php:52 +msgid "" +"Prior to Subscriptions 2.1, they were not easy to answer. Subscriptions 2.1 " +"introduces new reports to answer these questions, and many more." +msgstr "" +"Avant Subscriptions 2.1, il n’était pas facile d’y répondre. Subscriptions 2." +"1 introduit de nouveaux rapports pour répondre à ces questions, et bien " +"d’autres." + +#: includes/upgrades/templates/wcs-about.php:51 +msgid "These are important questions for any subscription commerce business." +msgstr "" +"Ce sont des questions importantes pour toute entreprise de commerce par " +"abonnement." + +#: includes/upgrades/templates/wcs-about.php:50 +msgid "" +"How many customers stay subscribed for more than 6 months? What is the " +"average lifetime value of your subscribers? How much renewal revenue will " +"your store earn next month?" +msgstr "" +"Combien de clients restent abonnés pendant plus de 6 mois ? Quelle est la " +"valeur moyenne de la durée de vie de vos abonnés ? Combien de revenus de " +"renouvellement votre boutique gagnera-t-elle le mois prochain ?" + +#: includes/upgrades/templates/wcs-about.php:49 +msgid "Subscription Reports" +msgstr "Rapports d’abonnement" + +#: includes/upgrades/templates/wcs-about.php:23 +msgid "" +"Version 2.1 introduces some great new features requested by store managers " +"just like you (and possibly even by %syou%s)." +msgstr "" +"La version 2.1 introduit de nouvelles fonctionnalités géniales demandées par " +"des gérants de boutique comme vous (et peut-être même par %svous%s)." + +#: includes/upgrades/templates/wcs-about.php:19 +msgid "Welcome to Subscriptions 2.1!" +msgstr "Bienvenue dans Subscriptions 2.1 !" + +#: includes/upgrades/class-wcs-upgrade-2-2-7.php:60 +msgid "Subscription end date in the past" +msgstr "Date de fin d’abonnement dans le passé" + +#: includes/payment-retry/class-wcs-retry-post-store.php:46 +msgid "No retries found" +msgstr "Aucune nouvelle tentative trouvée" + +#: includes/payment-retry/class-wcs-retry-post-store.php:45 +msgid "Search Renewal Payment Retries" +msgstr "Rechercher de nouvelles tentatives de paiement de renouvellement" + +#: includes/payment-retry/class-wcs-retry-post-store.php:43 +#: includes/payment-retry/class-wcs-retry-post-store.php:44 +msgid "View Retry" +msgstr "Voir la nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:42 +msgid "New Retry" +msgstr "Nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:41 +msgid "Edit Retry" +msgstr "Modifier la nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:39 +msgid "Add New Retry" +msgstr "Ajouter une nouvelle tentative" + +#: includes/payment-retry/class-wcs-retry-post-store.php:36 +msgid "Renewal Payment Retry" +msgstr "Nouvelle tentative de paiement de renouvellement" + +#: includes/payment-retry/class-wcs-retry-post-store.php:25 +msgid "" +"Payment retry posts store details about the automatic retry of failed " +"renewal payments." +msgstr "" +"La nouvelle tentative de paiement sauvegarde les détails sur la nouvelle " +"tentative automatique des paiements de renouvellement échoués." + +#. translators: 1,2: opening/closing link tags (to documentation). +#: includes/payment-retry/class-wcs-retry-admin.php:150 +msgid "" +"Attempt to recover recurring revenue that would otherwise be lost due to " +"payment methods being declined only temporarily. %1$sLearn more%2$s." +msgstr "" +"Tentative de récupération des revenus récurrents qui seraient autrement " +"perdus en raison du refus temporaire des moyens de paiement. %1$sEn savoir " +"plus%2$s." + +#: includes/payment-retry/class-wcs-retry-admin.php:145 +msgid "Enable automatic retry of failed recurring payments" +msgstr "" +"Activer la nouvelle tentative automatique des paiements de renouvellement " +"échoués" + +#: includes/payment-retry/class-wcs-retry-admin.php:144 +msgid "Retry Failed Payments" +msgstr "Retenter les paiements échoués" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:116 +msgid "%d Cancelled Payment Retry" +msgid_plural "%d Cancelled Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement annulée" +msgstr[1] "%d Nouvelles tentatives de paiement annulées" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:112 +msgid "%d Successful Payment Retry" +msgid_plural "%d Successful Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement réussie" +msgstr[1] "%d Nouvelles tentatives de paiement réussies" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:108 +msgid "%d Failed Payment Retry" +msgid_plural "%d Failed Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement échouée" +msgstr[1] "%d Nouvelles tentatives de paiement échouées" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:104 +msgid "%d Processing Payment Retry" +msgid_plural "%d Processing Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement en cours de traitement" +msgstr[1] "%d Nouvelles tentatives de paiement en cours de traitement" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:100 +msgid "%d Pending Payment Retry" +msgid_plural "%d Pending Payment Retries" +msgstr[0] "%d Nouvelle tentative de paiement en attente" +msgstr[1] "%d Nouvelles tentatives de paiement en attente" + +#: includes/payment-retry/class-wcs-retry-admin.php:46 +msgid "Automatic Failed Payment Retries" +msgstr "Nouvelles tentatives automatiques de paiement échoué" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:113 +msgid "PayPal API error - credentials are incorrect." +msgstr "Erreur d’API PayPal - les identifiants de connexion sont incorrects." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:641 +msgid "Invalid PayPal IPN Payload: unable to find matching subscription." +msgstr "" +"Charge utile PayPal IPN non valide : abonnement correspondant introuvable." + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:286 +msgid "PayPal Subscription ID:" +msgstr "ID d’abonnement PayPal :" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:194 +msgid "Ignore this error (not recommended)" +msgstr "Ignorer cette erreur (non recommandé)" + +#: includes/emails/class-wcs-email-payment-retry.php:30 +msgid "" +"[{site_title}] Automatic payment failed for {order_number}, retry scheduled " +"to run {retry_time}" +msgstr "" +"[{site_title}] Paiement automatique échoué pour {order_number}, nouvelle " +"tentative planifiée le {retry_time}" + +#: includes/emails/class-wcs-email-payment-retry.php:29 +msgid "Automatic renewal payment failed" +msgstr "Paiement de renouvellement automatique échoué" + +#: includes/emails/class-wcs-email-payment-retry.php:27 +msgid "" +"Payment retry emails are sent to chosen recipient(s) when an attempt to " +"automatically process a subscription renewal payment has failed and a retry " +"rule has been applied to retry the payment in the future." +msgstr "" +"Les e-mails de nouvelle tentative de paiement sont envoyés au(x) " +"destinataire(s) choisi(s) lorsqu’une tentative de traitement automatique " +"d’un paiement de renouvellement d’abonnement a échoué et qu’une règle de " +"nouvelle tentative a été appliquée pour retenter le paiement à l’avenir." + +#: includes/emails/class-wcs-email-payment-retry.php:26 +msgid "Payment Retry" +msgstr "Nouvelle tentative de paiement" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:29 +msgid "Subscription Suspended" +msgstr "Abonnement suspendu" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:27 +msgid "" +"Suspended Subscription emails are sent when a customer manually suspends " +"their subscription." +msgstr "" +"Des e-mails Abonnement suspendu sont envoyés lorsqu’un client suspend " +"manuellement son abonnement." + +#: includes/emails/class-wcs-email-on-hold-subscription.php:26 +msgid "Suspended Subscription" +msgstr "Abonnement suspendu" + +#: includes/emails/class-wcs-email-expired-subscription.php:78 +#: includes/emails/class-wcs-email-on-hold-subscription.php:78 +msgid "Subscription argument passed in is not an object." +msgstr "L’argument d’abonnement transmis n’est pas un objet." + +#: includes/emails/class-wcs-email-expired-subscription.php:29 +msgid "Subscription Expired" +msgstr "Abonnement expiré" + +#: includes/emails/class-wcs-email-expired-subscription.php:27 +msgid "" +"Expired Subscription emails are sent when a customer's subscription expires." +msgstr "" +"Des e-mails Abonnement expiré sont envoyés lorsque l’abonnement d’un client " +"expire." + +#: includes/emails/class-wcs-email-expired-subscription.php:26 +msgid "Expired Subscription" +msgstr "Abonnement expiré" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:41 +msgid "" +"Sent to a customer when the subscription is due for renewal and the renewal " +"requires a manual payment, either because it uses manual renewals or the " +"automatic recurring payment failed for the initial attempt and all automatic " +"retries (if any). The email contains renewal order information and payment " +"links." +msgstr "" +"Envoyé à un client lorsque l’abonnement doit être renouvelé et que le " +"renouvellement nécessite un paiement manuel, soit parce qu’il utilise des " +"renouvellements manuels, soit parce que le paiement récurrent automatique a " +"échoué à la première tentative et toutes les nouvelles tentatives " +"automatiques (le cas échéant). L’e-mail contient des informations sur la " +"commande de renouvellement et des liens de paiement." + +#: includes/emails/class-wcs-email-customer-payment-retry.php:33 +msgid "Automatic payment failed for order {order_number}" +msgstr "Paiement automatique échoué pour la commande {order_number}" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:32 +msgid "Automatic payment failed for {order_number}, we will retry {retry_time}" +msgstr "" +"Paiement automatique échoué pour {order_number}, nous retenterons le " +"{retry_time}" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:25 +msgid "" +"Sent to a customer when an attempt to automatically process a subscription " +"renewal payment has failed and a retry rule has been applied to retry the " +"payment in the future. The email contains the renewal order information, " +"date of the scheduled retry and payment links to allow the customer to pay " +"for the renewal order manually instead of waiting for the automatic retry." +msgstr "" +"Envoyé à un client lorsqu’une tentative de traitement automatique d’un " +"paiement de renouvellement d’abonnement a échoué et qu’une règle de nouvelle " +"tentative a été appliquée pour retenter le paiement à l’avenir. L’e-mail " +"contient des informations sur la commande de renouvellement, la date de la " +"nouvelle tentative planifiée et des liens de paiement pour permettre au " +"client de payer la commande de renouvellement manuellement au lieu " +"d’attendre la nouvelle tentative automatique." + +#: includes/emails/class-wcs-email-customer-payment-retry.php:24 +msgid "Customer Payment Retry" +msgstr "Nouvelle tentative de paiement du client" + +#: includes/class-wcs-webhooks.php:113 +msgid " Subscription switched" +msgstr "Abonnement changé" + +#: includes/class-wcs-query.php:297 +msgid "Endpoint for the My Account → View Subscription page" +msgstr "" +"Point de terminaison pour la page Mon compte → Afficher l’abonnement" + +#: includes/class-wcs-query.php:288 +msgid "Endpoint for the My Account → Subscriptions page" +msgstr "Point de terminaison pour la page Mon compte → Abonnements" + +#: includes/class-wcs-query.php:131 +msgid "My Subscription" +msgstr "Mon abonnement" + +#. translators: $1: the token/credit card label, 2$-3$: opening and closing +#. strong and link tags +#: includes/class-wcs-my-account-payment-methods.php:103 +msgid "" +"The deleted payment method was used for automatic subscription payments. To " +"avoid failed renewal payments in future the subscriptions using this payment " +"method have been updated to use your %1$s. To change the payment method of " +"individual subscriptions go to your %2$sMy Account > Subscriptions%3$s page." +msgstr "" +"Le moyen de paiement supprimé était utilisé pour les paiements d’abonnement " +"automatiques. Pour éviter l’échec des paiements de renouvellement à l’avenir," +" les abonnements utilisant ce moyen de paiement ont été mis à jour pour " +"utiliser votre %1$s. Pour modifier le moyen de paiement d’abonnements " +"individuels, allez sur la page %2$sMon compte > Abonnements%3$s." + +#: includes/class-wcs-my-account-payment-methods.php:80 +msgid "" +"The deleted payment method was used for automatic subscription payments, we " +"couldn't find an alternative token payment method token to change your " +"subscriptions to." +msgstr "" +"Le moyen de paiement supprimé était utilisé pour les paiements d’abonnement " +"automatiques. Nous n’avons pas pu trouver un autre jeton de moyen de " +"paiement pour modifier vos abonnements." + +#. translators: %s: order number. +#: includes/class-wcs-cart-resubscribe.php:320 +msgid "Customer resubscribed in order #%s" +msgstr "Client réabonné dans la commande n°%s" + +#: includes/class-wcs-cart-renewal.php:227 +msgid "Complete checkout to renew your subscription." +msgstr "Terminez la validation de commande pour renouveler votre abonnement." + +#: includes/class-wcs-cached-data-manager.php:225 +msgid "Weekly" +msgstr "Hebdomadaire" + +#: includes/class-wc-subscriptions-synchroniser.php:311 +msgid "Month for Synchronisation" +msgstr "Mois de synchronisation" + +#: includes/class-wc-subscriptions-synchroniser.php:48 +msgid "Synchronise renewals" +msgstr "Synchroniser les renouvellements" + +#: includes/class-wc-subscriptions-switcher.php:1974 +msgid "The item on the switch order cannot be found." +msgstr "L’article sur la commande de changement est introuvable." + +#: includes/class-wc-subscriptions-switcher.php:1972 +msgid "The original subscription item being switched cannot be found." +msgstr "" +"L’article d’abonnement original en cours de changement est introuvable." + +#: includes/class-wc-subscriptions-switcher.php:1377 +msgid "You can only switch to a subscription product." +msgstr "Vous pouvez passer uniquement à un produit d’abonnement." + +#. translators: %s: order number. +#: includes/class-wc-subscriptions-switcher.php:1126 +msgid "Switch order cancelled due to a new switch order being created #%s." +msgstr "" +"Commande de changement annulée en raison d’une nouvelle commande de " +"changement créée n° %s." + +#: includes/class-wc-subscriptions-order.php:745 +msgid "All orders types" +msgstr "Tous les types de commande" + +#: includes/class-wc-subscriptions-order.php:473 +msgid "Parent Order" +msgstr "Commande parente" + +#: includes/class-wc-subscriptions-order.php:471 +msgid "Resubscribe Order" +msgstr "Commande de réabonnement" + +#: includes/class-wc-subscriptions-order.php:469 +msgid "Renewal Order" +msgstr "Commande de renouvellement" + +#: includes/class-wc-subscriptions-order.php:449 +msgid "Subscription Relationship" +msgstr "Relation d’abonnement" + +#. translators: placeholder is a subscription ID. +#. translators: %d: subscription ID. +#: includes/class-wc-subscriptions-manager.php:167 +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:215 +msgid "Subscription doesn't exist in scheduled action: %d" +msgstr "L’abonnement n’existe pas dans l’action planifiée : %d" + +#. translators: placeholder is an order note. +#: includes/class-wc-subscriptions-manager.php:124 +msgid "Error: Unable to create renewal order with note \"%s\"" +msgstr "" +"Erreur : impossible de créer une commande de renouvellement avec la note " +"« %s »" + +#: includes/class-wc-subscriptions-coupon.php:714 +msgid "Renewal Discount" +msgstr "Remise sur le renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:696 +msgid "Renewal cart discount" +msgstr "Remise sur le panier de renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:695 +msgid "Renewal product discount" +msgstr "Remise sur le produit de renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:694 +msgid "Renewal % discount" +msgstr "Remise % sur le renouvellement" + +#: includes/class-wc-subscriptions-coupon.php:512 +msgid "Sorry, only recurring coupons can be applied to subscriptions." +msgstr "" +"Désolé, seuls les codes promo récurrents peuvent être appliqués aux " +"abonnements." + +#. translators: placeholder is coupon code +#: includes/class-wc-subscriptions-coupon.php:509 +msgid "" +"Sorry, \"%s\" can only be applied to subscription parent orders which " +"contain a product with signup fees." +msgstr "" +"Désolé, « %s » ne peut être appliqué qu’aux commandes parentes d’abonnement " +"qui contiennent un produit avec des frais d’inscription." + +#: includes/class-wc-subscriptions-coupon.php:505 +msgid "" +"Sorry, recurring coupons can only be applied to subscriptions or " +"subscription orders." +msgstr "" +"Désolé, les codes promo récurrents ne peuvent être appliqués qu’à des " +"abonnements ou des commandes d’abonnement." + +#: includes/class-wc-subscriptions-cart.php:1240 +msgid "Invalid recurring shipping method." +msgstr "Méthode de livraison récurrente non valide." + +#: includes/class-wc-subscription.php:2462 +#: includes/class-wc-subscriptions-checkout.php:343 +msgid "Backordered" +msgstr "En cours d’approvisionnement" + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2410 +msgid "The %s date must occur after the cancellation date." +msgstr "La date de %s doit être postérieure à la date d’annulation." + +#. translators: %d: subscription ID. +#. translators: %d: order ID. +#: includes/class-wc-subscription.php:1343 +#: includes/class-wc-subscription.php:2442 +msgid "Subscription #%d: " +msgstr "Abonnement n° %d :" + +#: includes/class-wc-subscription.php:1213 +msgid "Not cancelled" +msgstr "Pas annulé" + +#. translators: %s: new order status +#: includes/class-wc-subscription.php:590 +msgid "Status set to %s." +msgstr "État défini sur %s." + +#. translators: 1: subscription status, 2: error message. +#: includes/class-wc-subscription.php:546 +msgid "Unable to change subscription status to \"%1$s\". Exception: %2$s" +msgstr "" +"Impossible de modifier l’état d’abonnement sur « %1$s ». Exception : %2$s" + +#. translators: placeholder is an error message. +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:242 +msgid "Cannot create subscription: %s." +msgstr "Impossible de créer l’abonnement : %s." + +#: includes/api/class-wc-rest-subscriptions-controller.php:541 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:388 +msgid "The subscription's end date." +msgstr "Date de fin de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:536 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:383 +msgid "The subscription's next payment date." +msgstr "Date du prochain paiement de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:531 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:378 +msgid "The subscription's trial date" +msgstr "Date d’essai de l’abonnement" + +#: includes/api/class-wc-rest-subscriptions-controller.php:526 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:373 +msgid "The subscription's start date." +msgstr "Date de début de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:519 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:366 +msgid "Payment gateway ID." +msgstr "ID de la passerelle de paiement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:514 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:361 +msgid "Subscription payment details." +msgstr "Détails de paiement de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:508 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:355 +msgid "Billing period for the subscription." +msgstr "Période de facturation de l’abonnement." + +#: includes/api/class-wc-rest-subscriptions-controller.php:503 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:350 +msgid "The number of billing periods between subscription renewals." +msgstr "" +"Nombre de périodes de facturation entre les renouvellements d’abonnement." + +#. translators: placeholder is an error message. +#: includes/api/class-wc-rest-subscriptions-controller.php:472 +#: includes/api/class-wc-rest-subscriptions-controller.php:778 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:287 +msgid "Updating subscription dates errored with message: %s" +msgstr "Erreur de mise à jour des dates d’abonnement avec le message : %s" + +#. translators: 1$: gateway id, 2$: error message +#: includes/api/class-wc-rest-subscriptions-controller.php:402 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336 +msgid "" +"Subscription payment method could not be set to %1$s with error message: %2$s" +msgstr "" +"Le moyen de paiement de l’abonnement n’a pas pu être défini sur %1$s avec le " +"message d’erreur : %2$s" + +#: includes/api/class-wc-rest-subscriptions-controller.php:184 +msgid "Customer ID is invalid." +msgstr "L’ID client est non valide." + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:256 +msgid "Renewals amount" +msgstr "Montant des renouvellements" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:247 +msgid "Renewals count" +msgstr "Nombre de renouvellements" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:182 +msgid "Next 7 Days" +msgstr "7 prochains jours" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:181 +msgid "Next Month" +msgstr "Mois suivant" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:180 +msgid "Next 30 Days" +msgstr "30 prochains jours" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:179 +msgid "Next 12 Months" +msgstr "12 prochains mois" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:103 +msgid "%s average renewal amount" +msgstr "%s montant de renouvellement moyen" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:89 +msgid "%s renewal income in this period" +msgstr "%s revenus de renouvellement sur cette période" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:295 +msgid "Recovered Renewal Revenue" +msgstr "Revenu de renouvellement récupéré" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:279 +msgid "Pending retries" +msgstr "Nouvelles tentatives en attente" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:263 +msgid "Failed retries" +msgstr "Nouvelles tentatives échouées" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:247 +msgid "Successful retries" +msgstr "Nouvelles tentatives réussies" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:145 +msgid "The number of renewal payment retries not yet processed." +msgstr "" +"Nombre de nouvelles tentatives de renouvellement de paiement non encore " +"traitées." + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:144 +msgid "%s retry attempts pending" +msgstr "%s nouvelles tentatives en attente" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:137 +msgid "" +"The number of renewal payment retries for this period which did not result " +"in a successful payment." +msgstr "" +"Nombre de nouvelles tentatives de paiement de renouvellement pour cette " +"période qui n’ont pas abouti à un paiement réussi." + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:136 +msgid "%s retry attempts failed" +msgstr "%s nouvelles tentatives échouées" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:129 +msgid "" +"The number of renewal payment retries for this period which were able to " +"process the payment which had previously failed one or more times." +msgstr "" +"Nombre de nouvelles tentatives de paiement de renouvellement pour cette " +"période qui ont pu traiter le paiement qui avait échoué précédemment une ou " +"plusieurs fois." + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:128 +msgid "%s retry attempts succeeded" +msgstr "%s nouvelles tentatives réussies" + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:122 +msgid "" +"The number of renewal orders which had a failed payment use the retry system." +msgstr "" +"Nombre de commandes de renouvellement dont le paiement échoué utilise le " +"système de nouvelle tentative." + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:121 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:96 +msgid "%s renewal orders" +msgstr "%s commandes de renouvellement" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:114 +msgid "" +"The total amount of revenue, including tax and shipping, recovered with the " +"failed payment retry system for renewal orders with a failed payment." +msgstr "" +"Montant total des revenus, y compris les frais d’expédition et de taxe, " +"récupéré avec le système de nouvelle tentative de paiement échoué pour les " +"commandes de renouvellement avec un paiement échoué." + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:113 +msgid "%s renewal revenue recovered" +msgstr "%s revenu de renouvellement récupéré" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:1004 +msgid "Renewal Totals" +msgstr "Totaux de renouvellements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:984 +msgid "Resubscribe Totals" +msgstr "Totaux de réabonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:964 +msgid "Signup Totals" +msgstr "Totaux d’inscriptions" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:949 +msgid "Cancellations" +msgstr "Annulations" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:901 +msgid "Number of renewals" +msgstr "Nombre de renouvellements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:886 +msgid "Number of resubscribes" +msgstr "Nombre de réabonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:871 +msgid "Subscriptions signups" +msgstr "Inscriptions d’abonnements" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:839 +msgid "Switched subscriptions" +msgstr "Abonnements changés" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:780 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:199 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:213 +msgid "Export CSV" +msgstr "Exporter un CSV" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:735 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:162 +msgid "Last 7 Days" +msgstr "7 derniers jours" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:734 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:161 +msgid "This Month" +msgstr "Ce mois-ci" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:733 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:160 +msgid "Last Month" +msgstr "Mois dernier" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:732 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:159 +msgid "Year" +msgstr "Année" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:718 +msgid "Change in subscriptions between the start and end of the period." +msgstr "Changement des abonnements entre le début et la fin de la période." + +#. translators: %s: subscription net loss (with percentage). +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:713 +msgid "%s net subscription loss" +msgstr "%s perte nette d’abonnement" + +#. translators: %s: subscription net gain (with percentage). +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:710 +msgid "%s net subscription gain" +msgstr "%s gain net d’abonnement" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:693 +msgid "" +"The number of subscriptions during this period with an end date in the " +"future and a status other than pending." +msgstr "" +"Nombre d’abonnements pendant cette période avec une date de fin dans le " +"futur et un état autre que en attente." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:667 +msgid "" +"The number of subscriptions which have either expired or reached the end of " +"the prepaid term if it was previously cancelled." +msgstr "" +"Nombre d’abonnements qui ont expiré ou ont atteint la fin du terme prépayé " +"s’il était précédemment annulé." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:645 +msgid "" +"The number of subscriptions cancelled by the customer or store manager " +"during this period. The pre-paid term may not yet have ended during this " +"period." +msgstr "" +"Nombre d’abonnements annulés par le client ou le gérant de la boutique " +"pendant cette période. Le terme prépayé peut ne pas être encore terminé " +"pendant cette période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:623 +msgid "" +"The number of subscriptions upgraded, downgraded or cross-graded during this " +"period." +msgstr "" +"Nombre d’abonnements mis à niveau, rétrogradés ou reclassés pendant cette " +"période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:601 +msgid "The number of renewal orders processed during this period." +msgstr "Nombre de commandes de renouvellement traitées pendant cette période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:579 +msgid "The number of resubscribe orders processed during this period." +msgstr "Nombre de commandes de réabonnement traitées pendant cette période." + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:557 +msgid "" +"The number of subscriptions purchased in parent orders created during this " +"period. This represents the new subscriptions created by customers placing " +"an order via checkout." +msgstr "" +"Nombre d’abonnements achetés dans les commandes parentes créées pendant " +"cette période. Cela représente les nouveaux abonnements créés par les " +"clients passant une commande via la validation de commande." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:505 +msgid "The sum of all resubscribe orders including tax and shipping." +msgstr "" +"Somme de toutes les commandes de réabonnement, incluant les frais " +"d’expédition et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:504 +msgid "%s resubscribe revenue in this period" +msgstr "%s revenu de réabonnement sur cette période" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:497 +msgid "The sum of all renewal orders including tax and shipping." +msgstr "" +"Somme de toutes les commandes de renouvellement, incluant les frais " +"d’expédition et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:496 +msgid "%s renewal revenue in this period" +msgstr "%s revenu de renouvellement sur cette période" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:489 +msgid "" +"The sum of all subscription parent orders, including other items, fees, tax " +"and shipping." +msgstr "" +"Somme de toutes les commandes parentes d’abonnement, incluant d’autres " +"articles, les frais, les frais d’expédition et de taxe." + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:488 +msgid "%s signup revenue in this period" +msgstr "%s revenu d’inscription sur cette période" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:300 +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:340 +msgid "subscriptions" +msgstr "abonnements" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:95 +msgid "The average line total on all orders for this product line item." +msgstr "" +"Total moyen de la ligne pour toutes les commandes de cet article dans la " +"ligne de produit." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:95 +msgid "Average Lifetime Value %s" +msgstr "Valeur moyenne de la durée de vie %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:93 +msgid "The average line total for this product on each subscription." +msgstr "Total moyen de la ligne pour ce produit sur chaque abonnement." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:93 +msgid "Average Recurring Line Total %s" +msgstr "Total moyen de la ligne récurrente %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:91 +msgid "" +"The number of subscriptions that include this product as a line item and " +"have a status other than pending or trashed." +msgstr "" +"Nombre d’abonnements qui incluent ce produit en tant qu'article de la ligne " +"et dont l’état n’est pas en attente ou déplacé vers la corbeille." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:91 +msgid "Subscription Count %s" +msgstr "Nombre d’abonnements %s" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:89 +msgid "Subscription Product" +msgstr "Produit d’abonnement" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:30 +msgid "No products found." +msgstr "Aucun produit trouvé." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:105 +msgid "The total value of this customer's sign-up, switch and renewal orders." +msgstr "" +"Valeur totale des commandes d’inscription, de changement et de " +"renouvellement de ce client." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:105 +msgid "Lifetime Value from Subscriptions %s" +msgstr "Valeur à vie des abonnements %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:103 +msgid "" +"The number of sign-up, switch and renewal orders this customer has placed " +"with your store with a paid status (i.e. processing or complete)." +msgstr "" +"Nombre des commandes d’inscription, de changement et de renouvellement " +"placées par ce client avec votre boutique avec un état payé (c.-à-d. en " +"cours de traitement ou terminé)." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:103 +msgid "Total Subscription Orders %s" +msgstr "Total des commandes d’abonnement %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:101 +msgid "" +"The number of subscriptions this customer has with a status other than " +"pending or trashed." +msgstr "" +"Nombre d’abonnements de ce client avec un état autre que en attente ou " +"déplacé vers la corbeille." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:101 +msgid "Total Subscriptions %s" +msgstr "Total des abonnements %s" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:99 +msgid "" +"The number of subscriptions this customer has with a status of active or " +"pending cancellation." +msgstr "" +"Nombre d’abonnements de ce client avec un état d’annulation active ou en " +"attente." + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:99 +msgid "Active Subscriptions %s" +msgstr "Abonnements actifs %s" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:48 +msgid "Average Lifetime Value" +msgstr "Valeur moyenne de la durée de vie" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:47 +msgid "Total Subscription Orders" +msgstr "Total des commandes d’abonnement" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:46 +msgid "Total Subscriptions" +msgstr "Total des abonnements" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:45 +msgid "Active Subscriptions" +msgstr "Abonnements actifs" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:44 +msgid "Total Subscribers" +msgstr "Total des abonnés" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:32 +msgid "No customers found." +msgstr "Aucun client." + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:23 +msgid "Customers" +msgstr "Clients" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:22 +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:97 +msgid "Customer" +msgstr "Client" + +#: includes/admin/reports/class-wcs-report-retention-rate.php:226 +msgid "Unended Subscription Count" +msgstr "Nombre d’abonnements non terminés" + +#. translators: %d refers to the number of times we have detected cache update +#. failures +#: includes/admin/reports/class-wcs-report-cache-manager.php:323 +msgid "%d failures" +msgid_plural "%d failure" +msgstr[0] "%d échecs" +msgstr[1] "%d échec" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:320 +msgid "Cache Update Failures" +msgstr "Échecs de mise à jour du cache" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:265 +msgid "" +"Please note: data for this report is cached. The data displayed may be out " +"of date by up to 24 hours. The cache is updated each morning at 4am in your " +"site's timezone." +msgstr "" +"Veuillez noter : les données de ce rapport sont mises en cache. Les données " +"affichées peuvent être obsolètes jusqu’à 24 heures. Le cache est mis à jour " +"chaque matin à 4 h dans le fuseau horaire de votre site." + +#: includes/admin/meta-boxes/views/html-retries-table.php:32 +msgid "" +"The email sent to the customer when the renewal payment or payment retry " +"failed to notify them that the payment would be retried." +msgstr "" +"E-mail envoyé au client lorsque le paiement de renouvellement ou la nouvelle " +"tentative de paiement n’a pas pu l’informer que le paiement serait retenté." + +#: includes/admin/meta-boxes/views/html-retries-table.php:28 +msgid "" +"The status applied to the subscription for the time between when the renewal " +"payment failed or last retry occurred and when this retry was processed." +msgstr "" +"État appliqué à l’abonnement pour le temps écoulé entre l’échec du paiement " +"de renouvellement ou la dernière tentative et le traitement de cette " +"nouvelle tentative." + +#: includes/admin/meta-boxes/views/html-retries-table.php:27 +msgid "Status of Subscription" +msgstr "État de l’abonnement" + +#: includes/admin/meta-boxes/views/html-retries-table.php:24 +msgid "" +"The status applied to the order for the time between when the renewal " +"payment failed or last retry occurred and when this retry was processed." +msgstr "" +"État appliqué à la commande pour le temps écoulé entre l’échec du paiement " +"de renouvellement ou la dernière tentative et le traitement de cette " +"nouvelle tentative." + +#: includes/admin/meta-boxes/views/html-retries-table.php:23 +msgid "Status of Order" +msgstr "État de la commande" + +#: includes/admin/meta-boxes/views/html-retries-table.php:20 +msgid "" +"The status of the automatic payment retry: pending means the retry will be " +"processed in the future, failed means the payment was not successful when " +"retried and completed means the payment succeeded when retried." +msgstr "" +"État de la nouvelle tentative de paiement automatique : en attente signifie " +"que la nouvelle tentative sera traitée à l’avenir, échoué signifie que le " +"paiement a échoué lors de la nouvelle tentative et terminé signifie que le " +"paiement a réussi lors de la nouvelle tentative." + +#: includes/admin/meta-boxes/views/html-retries-table.php:19 +msgid "Retry Status" +msgstr "État de la nouvelle tentative" + +#: includes/admin/meta-boxes/views/html-retries-table.php:17 +msgid "Retry Date" +msgstr "Date de la nouvelle tentative" + +#. translators: placeholder is error message from the payment gateway or +#. subscriptions when updating the status +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:401 +msgid "Error updating some information: %s" +msgstr "Erreur lors de la mise à jour de certaines informations : %s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:264 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:294 +msgid "Customer Provided Note" +msgstr "Note fournie par le client" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:231 +msgid "Load shipping address" +msgstr "Charger l’adresse de livraison" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:140 +msgid "Load billing address" +msgstr "Charger l’adresse de facturation" + +#. Author of the plugin +#: includes/admin/class-wcs-admin-reports.php:104 +#: includes/admin/reports/class-wcs-report-cache-manager.php:262 +msgid "WooCommerce" +msgstr "WooCommerce" + +#: includes/admin/class-wcs-admin-reports.php:83 +msgid "Failed Payment Retries" +msgstr "Nouvelles tentatives de paiement échouées" + +#: includes/admin/class-wcs-admin-reports.php:73 +msgid "Subscriptions by Customer" +msgstr "Abonnements par client" + +#: includes/admin/class-wcs-admin-reports.php:67 +msgid "Subscriptions by Product" +msgstr "Abonnements par produit" + +#: includes/admin/class-wcs-admin-reports.php:61 +msgid "Retention Rate" +msgstr "Taux de conservation" + +#: includes/admin/class-wcs-admin-reports.php:55 +msgid "Upcoming Recurring Revenue" +msgstr "Revenus récurrents à venir" + +#: includes/admin/class-wcs-admin-reports.php:49 +msgid "Subscription Events by Date" +msgstr "Événements d’abonnement par date" + +#. translators: 1: user display name 2: user ID 3: user email +#: includes/admin/class-wcs-admin-post-types.php:1107 +msgid "%1$s (#%2$s – %3$s)" +msgstr "%1$s (n°%2$s – %3$s)" + +#: includes/admin/class-wcs-admin-post-types.php:654 +msgid "" +"This date should be treated as an estimate only. The payment gateway for " +"this subscription controls when payments are processed." +msgstr "" +"Cette date ne doit être considérée que comme une estimation. La passerelle " +"de paiement pour cet abonnement contrôle le moment où les paiements sont " +"traités." + +#: includes/admin/class-wcs-admin-post-types.php:651 +msgid "Y/m/d g:i:s A" +msgstr "" +"d/m/Y à G h i mi\n" +" s s" + +#: includes/admin/class-wcs-admin-post-types.php:569 +msgid "Show more details" +msgstr "Afficher plus de détails" + +#: includes/admin/class-wcs-admin-post-types.php:429 +msgid "Last Order Date" +msgstr "Date de la dernière commande" + +#: includes/admin/class-wcs-admin-meta-boxes.php:187 +msgid "Retry Renewal Payment" +msgstr "Retenter le paiement de renouvellement" + +#: includes/admin/class-wcs-admin-meta-boxes.php:144 +msgid "" +"Are you sure you want to retry payment for this renewal order?\n" +"\n" +"This will attempt to charge the customer and send renewal order emails (if " +"emails are enabled)." +msgstr "" +"Voulez-vous vraiment retenter le paiement pour cette commande de " +"renouvellement ?\n" +"\n" +"Cela tentera de facturer le client et d’envoyer des e-mails de commande de " +"renouvellement (si les e-mails sont activés)." + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1925 +msgid "" +"Payment gateways which don't support automatic recurring payments can be " +"used to process %1$smanual subscription renewal payments%2$s." +msgstr "" +"Les passerelles de paiement qui ne prennent pas en charge les paiements " +"récurrents automatiques peuvent être utilisées pour traiter les " +"%1$spaiements de renouvellement d’abonnement manuels%2$s." + +#: includes/admin/class-wc-subscriptions-admin.php:1917 +msgid "Recurring Payments" +msgstr "Paiements récurrents" + +#. translators: $1-2: opening and closing tags of a link that takes to Woo +#. marketplace / Stripe product page +#: includes/admin/class-wc-subscriptions-admin.php:1912 +msgid "" +"No payment gateways capable of processing automatic subscription payments " +"are enabled. If you would like to process automatic payments, we recommend " +"the %1$sfree Stripe extension%2$s." +msgstr "" +"Aucune passerelle de paiement capable de traiter les paiements d’abonnement " +"automatique n’est activée. Si vous voulez traiter les paiements automatiques," +" nous vous recommandons l’%1$sextension Stripe gratuite%2$s." + +#: includes/admin/class-wc-subscriptions-admin.php:1893 +msgid "" +"This subscription is no longer editable because the payment gateway does not " +"allow modification of recurring amounts." +msgstr "" +"Cet abonnement n’est plus modifiable car la passerelle de paiement " +"n’autorise pas la modification des montants récurrents." + +#: includes/admin/class-wc-subscriptions-admin.php:1889 +msgid "Subscription items can no longer be edited." +msgstr "Les articles d’abonnement ne peuvent plus être modifiés." + +#: includes/admin/class-wc-subscriptions-admin.php:1335 +msgid "" +"Allow a subscription product to be purchased with other products and " +"subscriptions in the same transaction." +msgstr "" +"Autoriser l’achat d’un produit d’abonnement avec d’autres produits et " +"abonnements dans la même transaction." + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1301 +msgid "" +"If you don't want new subscription purchases to automatically charge renewal " +"payments, you can turn off automatic payments. Existing automatic " +"subscriptions will continue to charge customers automatically. %1$sLearn " +"more%2$s." +msgstr "" +"Si vous ne souhaitez pas que les nouveaux achats d’abonnement facturent " +"automatiquement les paiements de renouvellement, vous pouvez désactiver les " +"paiements automatiques. Les abonnements automatiques existants continueront " +"de facturer les clients automatiquement. %1$sEn savoir plus%2$s." + +#. translators: %s: subscription status. +#: includes/admin/class-wc-subscriptions-admin.php:778 +msgid "" +"Unable to change subscription status to \"%s\". Please assign a customer to " +"the subscription to activate it." +msgstr "" +"Impossible de modifier l’état d’abonnement sur « %s ». Veuillez assigner un " +"client à l’abonnement pour l’activer." + +#: includes/admin/class-wc-subscriptions-admin.php:330 +msgid "" +"Automatically expire the subscription after this length of time. This length " +"is in addition to any free trial or amount of time provided before a " +"synchronised first renewal date." +msgstr "" +"Expire automatiquement l’abonnement après cette durée. Cette durée s’ajoute " +"à tout essai gratuit ou à toute durée accordée avant une première date de " +"renouvellement synchronisée." + +#: includes/admin/class-wc-subscriptions-admin.php:327 +#: includes/admin/class-wc-subscriptions-admin.php:451 +#: templates/admin/html-variation-price.php:66 +msgid "Expire after" +msgstr "Expire après" + +#: includes/admin/class-wc-subscriptions-admin.php:306 +msgid "Subscription interval" +msgstr "Intervalle d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:285 +msgid "Choose the subscription price, billing interval and period." +msgstr "" +"Choisissez le prix de l’abonnement, l’intervalle de facturation et la " +"période." + +#: tests/unit/scheduler/scheduler.php:66 wcs-functions.php:304 +msgctxt "table heading" +msgid "Trial End" +msgstr "Fin de l’essai" + +#: wcs-functions.php:277 +msgid "Can not get address type display name. Address type is not a string." +msgstr "" +"Impossible d’obtenir le nom d’affichage du type d’adresse. Le type d’adresse " +"n’est pas une chaîne." + +#. translators: placeholder is order date parsed by strftime +#: wcs-functions.php:163 +msgctxt "The post title for the new subscription" +msgid "Subscription – %s" +msgstr "Abonnement – %s" + +#: wcs-functions.php:142 +msgctxt "Error message while creating a subscription" +msgid "Invalid subscription customer_id." +msgstr "Abonnement non valide customer_id." + +#: wcs-functions.php:132 +msgctxt "Error message while creating a subscription" +msgid "Subscription created date must be before current day." +msgstr "" +"La date de création de l’abonnement doit être antérieure au jour en cours." + +#: wcs-functions.php:137 +msgctxt "Error message while creating a subscription" +msgid "" +"Invalid date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +msgstr "" +"Date non valide. La date doit être une chaîne au format : « Y-m-d H:i:s »." + +#: templates/single-product/add-to-cart/variable-subscription.php:23 +msgid "This product is currently out of stock and unavailable." +msgstr "Ce produit est actuellement en rupture et indisponible." + +#. translators: $1: formatted order total for the order, $2: number of items +#. bought +#: templates/myaccount/related-orders.php:56 +msgid "%1$s for %2$d item" +msgid_plural "%1$s for %2$d items" +msgstr[0] "%1$s pour %2$d article" +msgstr[1] "%1$s pour %2$d articles" + +#: templates/myaccount/my-subscriptions.php:46 +#: templates/myaccount/related-orders.php:53 +#: templates/myaccount/related-subscriptions.php:42 +msgctxt "Used in data attribute. Escaped" +msgid "Total" +msgstr "Total" + +#: templates/myaccount/my-subscriptions.php:40 +#: tests/unit/scheduler/scheduler.php:67 wcs-functions.php:305 +msgctxt "table heading" +msgid "Next Payment" +msgstr "Paiement suivant" + +#: tests/unit/scheduler/scheduler.php:70 wcs-functions.php:308 +msgctxt "table heading" +msgid "End Date" +msgstr "Date de fin" + +#: tests/unit/scheduler/scheduler.php:65 wcs-functions.php:303 +msgctxt "table heading" +msgid "Start Date" +msgstr "Date de début" + +#. translators: placeholder is localised start date +#: templates/emails/plain/subscription-info.php:29 +msgctxt "in plain emails for subscription information" +msgid "Start date: %s" +msgstr "" + +#. translators: placeholder is localised end date, or "when cancelled" +#: templates/emails/plain/subscription-info.php:33 +msgctxt "in plain emails for subscription information" +msgid "End date: %s" +msgstr "Date de fin : %s" + +#: templates/emails/plain/subscription-info.php:31 +msgctxt "Used as end date for an indefinite subscription" +msgid "When Cancelled" +msgstr "En cas d’annulation" + +#. translators: placeholder is the formatted order total for the subscription +#: templates/emails/plain/subscription-info.php:35 +msgctxt "in plain emails for subscription information" +msgid "Recurring price: %s" +msgstr "Prix récurrent : %s" + +#. translators: placeholder is subscription's number +#: templates/emails/plain/subscription-info.php:25 +msgctxt "in plain emails for subscription information" +msgid "Subscription: %s" +msgstr "Abonnement : %s" + +#: templates/emails/plain/cancelled-subscription.php:44 +#: templates/emails/plain/expired-subscription.php:44 +#: templates/emails/plain/on-hold-subscription.php:40 +msgctxt "in plain emails for subscription information" +msgid "View Subscription: %s" +msgstr "Afficher l’abonnement : %s" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, +#. note: no full stop due to url at the end +#: templates/emails/customer-renewal-invoice.php:31 +#: templates/emails/plain/customer-renewal-invoice.php:23 +msgctxt "In customer renewal invoice email" +msgid "" +"The automatic payment to renew your subscription with %1$s has failed. To " +"reactivate the subscription, please log in and pay for the renewal from your " +"account page: %2$s" +msgstr "" +"Le paiement automatique pour renouveler votre abonnement avec %1$s a échoué. " +"Pour réactiver l’abonnement, veuillez vous connecter et payer le " +"renouvellement sur la page de votre compte : %2$s" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, +#. note: no full stop due to url at the end +#: templates/emails/customer-renewal-invoice.php:22 +#: templates/emails/plain/customer-renewal-invoice.php:20 +msgctxt "In customer renewal invoice email" +msgid "" +"An order has been created for you to renew your subscription on %1$s. To pay " +"for this invoice please use the following link: %2$s" +msgstr "" +"Une commande a été créée pour vous afin de renouveler votre abonnement sur " +"%1$s. Pour payer cette facture, veuillez utiliser le lien suivant : %2$s" + +#: templates/emails/cancelled-subscription.php:24 +msgctxt "table headings in notification email" +msgid "End of Prepaid Term" +msgstr "Fin du terme prépayé" + +#: templates/myaccount/my-subscriptions.php:23 +#: templates/myaccount/related-subscriptions.php:23 +#: templates/myaccount/related-subscriptions.php:39 +msgctxt "table heading" +msgid "Next payment" +msgstr "Paiement suivant" + +#. translators: $1: customer's first name and last name, $2: how many +#. subscriptions customer switched +#: templates/emails/admin-new-switch-order.php:18 +#: templates/emails/plain/admin-new-switch-order.php:18 +msgctxt "Used in switch notification admin email" +msgid "" +"Customer %1$s has switched their subscription. The details of their new " +"subscription are as follows:" +msgid_plural "" +"Customer %1$s has switched %2$d of their subscriptions. The details of their " +"new subscriptions are as follows:" +msgstr[0] "" +"Le client %1$s a changé son abonnement. Les détails de son nouvel abonnement " +"sont les suivants :" +msgstr[1] "" +"Le client %1$s a changé %2$d de ses abonnements. Les détails de ses nouveaux " +"abonnements sont les suivants :" + +#: templates/emails/cancelled-subscription.php:22 +#: templates/emails/email-order-details.php:38 +#: templates/emails/expired-subscription.php:22 +#: templates/emails/on-hold-subscription.php:22 +msgctxt "table headings in notification email" +msgid "Price" +msgstr "Prix" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/admin-new-renewal-order.php:16 +#: templates/emails/plain/admin-new-renewal-order.php:16 +msgctxt "Used in admin email: new renewal order" +msgid "" +"You have received a subscription renewal order from %1$s. Their order is as " +"follows:" +msgstr "" +"Vous avez reçu une commande de renouvellement d’abonnement de %1$s. Voici sa " +"commande :" + +#: templates/checkout/form-change-payment-method.php:47 +msgctxt "text on button on checkout page" +msgid "Change payment method" +msgstr "Modifier le moyen de paiement" + +#: templates/checkout/form-change-payment-method.php:22 +msgctxt "table headings in notification email" +msgid "Totals" +msgstr "Totaux" + +#: templates/checkout/form-change-payment-method.php:21 +#: templates/emails/email-order-details.php:37 +msgctxt "table headings in notification email" +msgid "Quantity" +msgstr "Quantité" + +#: templates/checkout/form-change-payment-method.php:20 +#: templates/emails/email-order-details.php:36 +#: templates/myaccount/subscription-totals-table.php:21 +msgctxt "table headings in notification email" +msgid "Product" +msgstr "Produit" + +#: templates/admin/html-variation-price.php:31 +msgid "Subscription trial period:" +msgstr "Période d’essai d’abonnement :" + +#: templates/admin/deprecated/html-variation-price.php:59 +msgctxt "" +"Edit product screen, between the Billing Period and Subscription Length " +"dropdowns" +msgid "for" +msgstr "pour" + +#: includes/wcs-time-functions.php:191 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "year" +msgid_plural "years" +msgstr[0] "année" +msgstr[1] "années" + +#: includes/wcs-time-functions.php:190 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "month" +msgid_plural "months" +msgstr[0] "mois" +msgstr[1] "mois" + +#: includes/wcs-time-functions.php:189 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "week" +msgid_plural "weeks" +msgstr[0] "semaine" +msgstr[1] "semaines" + +#: includes/wcs-time-functions.php:188 +msgctxt "" +"Used in the trial period dropdown. Number is in text field. 0, 2+ will need " +"plural, 1 will need singular." +msgid "day" +msgid_plural "days" +msgstr[0] "jour" +msgstr[1] "jours" + +#. translators: period interval, placeholder is ordinal (eg "$10 every +#. _2nd/3rd/4th_", etc) +#: includes/wcs-time-functions.php:163 +msgctxt "period interval with ordinal number (e.g. \"every 2nd\"" +msgid "every %s" +msgstr "chaque %s" + +#: includes/wcs-time-functions.php:105 +msgctxt "Subscription lengths. e.g. \"For 1 year...\"" +msgid "1 year" +msgstr "1 an" + +#: includes/wcs-time-functions.php:101 +msgctxt "Subscription lengths. e.g. \"For 1 month...\"" +msgid "1 month" +msgstr "1 mois" + +#: includes/wcs-time-functions.php:97 +msgctxt "Subscription lengths. e.g. \"For 1 week...\"" +msgid "1 week" +msgstr "1 semaine" + +#: includes/wcs-time-functions.php:93 +msgctxt "Subscription lengths. e.g. \"For 1 day...\"" +msgid "1 day" +msgstr "1 jour" + +#. translators: placeholder is number of years. (e.g. "Bill this every year / 4 +#. years") +#: includes/wcs-time-functions.php:37 +msgctxt "Subscription billing period." +msgid "year" +msgid_plural "%s years" +msgstr[0] "année" +msgstr[1] "%s années" + +#. translators: placeholder is number of months. (e.g. "Bill this every month +#. 4 months") +#: includes/wcs-time-functions.php:35 +msgctxt "Subscription billing period." +msgid "month" +msgid_plural "%s months" +msgstr[0] "mois" +msgstr[1] "%s mois" + +#. translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 +#. weeks") +#: includes/wcs-time-functions.php:33 +msgctxt "Subscription billing period." +msgid "week" +msgid_plural "%s weeks" +msgstr[0] "semaine" +msgstr[1] "%s semaines" + +#. translators: placeholder is number of days. (e.g. "Bill this every day / 4 +#. days") +#: includes/wcs-time-functions.php:31 +msgctxt "Subscription billing period." +msgid "day" +msgid_plural "%s days" +msgstr[0] "jour" +msgstr[1] "%s jours" + +#: includes/wcs-order-functions.php:152 +msgctxt "" +"Refers to the type of the copy being performed: \"copy_order\", " +"\"subscription\", \"renewal_order\", \"resubscribe_order\"" +msgid "Invalid data. Type of copy is not a string." +msgstr "Données non valides. Le type de copie n’est pas une chaîne." + +#: includes/wcs-order-functions.php:148 +msgctxt "" +"In wcs_copy_order_meta error message. Refers to origin and target order " +"objects." +msgid "Invalid data. Orders expected aren't orders." +msgstr "" +"Données non valides. Les commandes attendues ne sont pas des commandes." + +#: includes/upgrades/templates/wcs-about-2-0.php:121 +msgctxt "h3 on the About Subscriptions page for this new feature" +msgid "Change Payment Method" +msgstr "Modifier le moyen de paiement" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, +#. 4$: break tag +#: includes/upgrades/class-wc-subscriptions-upgrader.php:436 +msgctxt "" +"Error message that gets sent to front end when upgrading Subscriptions" +msgid "" +"Unable to repair subscriptions.%4$sError: %1$s%4$sPlease refresh the page " +"and try again. If problem persists, %2$scontact support%3$s." +msgstr "" +"Impossible de réparer les abonnements.%4$sErreur : %1$s%4$sVeuillez " +"rafraîchir la page et réessayer. Si le problème persiste, %2$scontactez " +"l’assistance%3$s." + +#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others +#. were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL +#. languages. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:417 +msgctxt "The assembled repair message that gets sent to front end." +msgid "%1$s%2$s %3$s" +msgstr "" + +#. translators: placeholder is "{execution_time}", which will be replaced on +#. front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:414 +msgctxt "Repair message that gets sent to front end." +msgid "(in %s seconds)" +msgstr "(en %s secondes)" + +#. translators: placeholder is number of subscriptions that were checked and +#. did not need repairs. There's a space at the beginning! +#: includes/upgrades/class-wc-subscriptions-upgrader.php:410 +msgctxt "Repair message that gets sent to front end." +msgid " %d other subscription was checked and did not need any repairs." +msgid_plural "" +"%d other subscriptions were checked and did not need any repairs." +msgstr[0] "" +" %d autre abonnement a été vérifié et ne nécessitait aucune réparation." +msgstr[1] "" +"%d autres abonnements ont été vérifiés et ne nécessitaient aucune réparation." + +#. translators: placeholder is the number of subscriptions repaired +#: includes/upgrades/class-wc-subscriptions-upgrader.php:404 +msgctxt "Repair message that gets sent to front end." +msgid "" +"Repaired %d subscriptions with incorrect dates, line tax data or missing " +"customer notes." +msgstr "" +"Réparation de %d abonnements avec des dates incorrectes, des données de " +"ligne de TVA ou des notes client manquantes." + +#. translators: placeholder is "{time_left}", will be replaced on front end +#. with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:379 +#: includes/upgrades/class-wc-subscriptions-upgrader.php:425 +msgctxt "Message that gets sent to front end." +msgid "Estimated time left (minutes:seconds): %s" +msgstr "Temps restant estimé (minutes:secondes) : %s" + +#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}", +#. will be replaced on front end with actual time it took +#: includes/upgrades/class-wc-subscriptions-upgrader.php:376 +msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)." +msgstr "" +"Migration de %1$s abonnements vers la nouvelle structure (en %2$s secondes)." + +#. translators: 1$: number of action scheduler hooks upgraded, 2$: +#. "{execution_time}", will be replaced on front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:364 +msgid "" +"Migrated %1$s subscription related hooks to the new scheduler (in %2$s " +"seconds)." +msgstr "" +"Migration de %1$s crochets liés à l’abonnement vers le nouveau planificateur " +"(en %2$s secondes)." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:275 +msgctxt "" +"when it is a payment change, and there is a subscr_signup message, this will " +"be a confirmation message that PayPal accepted it being the new payment " +"method" +msgid "IPN subscription payment method changed to PayPal." +msgstr "Le moyen de paiement d’abonnement IPN a été remplacé par PayPal." + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:150 +#: templates/admin/deprecated/order-shipping-html.php:14 +#: templates/admin/deprecated/order-tax-html.php:9 +msgctxt "no information about something" +msgid "N/A" +msgstr "ND" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:138 +msgctxt "used in api error message if there is no long message" +msgid "Unknown error" +msgstr "Erreur inconnue" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:136 +msgctxt "used in api error message if there is no severity code from PayPal" +msgid "Error" +msgstr "Erreur" + +#: includes/gateways/paypal/class-wcs-paypal.php:626 +msgctxt "" +"used in User Agent data sent to PayPal to help identify where a payment came " +"from" +msgid "WooCommerce Subscriptions PayPal" +msgstr "WooCommerce Subscriptions PayPal" + +#: includes/gateways/paypal/class-wcs-paypal.php:362 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:320 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:336 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:384 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:150 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:156 +msgctxt "" +"hash before the order number. Used as a character to remove from the actual " +"order number" +msgid "#" +msgstr "n°" + +#. translators: $1: {blogname}, $2: {order_date}, variables will be substituted +#. when email is sent out +#: includes/emails/class-wcs-email-completed-renewal-order.php:40 +msgctxt "Default email subject for email with downloadable files in it" +msgid "" +"Your %1$s subscription renewal order from %2$s is complete - download your " +"files" +msgstr "" +"Votre commande de renouvellement d’abonnement de %1$s du %2$s est terminée, " +"téléchargez vos fichiers" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:38 +msgctxt "Default email heading for email with downloadable files in it" +msgid "Your subscription renewal order is complete - download your files" +msgstr "" +"Votre commande de renouvellement d’abonnement est terminée, téléchargez vos " +"fichiers" + +#. translators: $1: {blogname}, $2: {order_date}, variables that will be +#. substituted when email is sent out +#: includes/emails/class-wcs-email-completed-renewal-order.php:31 +msgctxt "" +"Default email subject for email to customer on completed renewal order" +msgid "Your %1$s renewal order from %2$s is complete" +msgstr "Votre commande de renouvellement de %1$s du %2$s est terminée" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:29 +msgctxt "" +"Default email heading for email to customer on completed renewal order" +msgid "Your renewal order is complete" +msgstr "Votre commande de renouvellement est terminée" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:173 +#: includes/emails/class-wcs-email-expired-subscription.php:171 +#: includes/emails/class-wcs-email-on-hold-subscription.php:171 +msgctxt "text, html or multipart" +msgid "Email type" +msgstr "Type d’e-mail" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:165 +#: includes/emails/class-wcs-email-expired-subscription.php:163 +#: includes/emails/class-wcs-email-on-hold-subscription.php:163 +msgctxt "" +"Name the setting that controls the main heading contained within the email " +"notification" +msgid "Email Heading" +msgstr "En-tête de l’e-mail" + +#. translators: placeholder is {blogname}, a variable that will be substituted +#. when email is sent out +#: includes/emails/class-wcs-email-cancelled-subscription.php:31 +msgctxt "default email subject for cancelled emails sent to the admin" +msgid "[%s] Subscription Cancelled" +msgstr "[%s] Abonnement annulé" + +#: includes/class-wcs-user-change-status-handler.php:77 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been cancelled." +msgstr "Votre abonnement a été annulé." + +#: includes/class-wcs-user-change-status-handler.php:76 +msgctxt "order note left on subscription after user action" +msgid "Subscription cancelled by the subscriber from their account page." +msgstr "Abonnement annulé par l’abonné sur sa page de compte." + +#: includes/class-wcs-user-change-status-handler.php:68 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been put on hold." +msgstr "Votre abonnement a été mis en attente." + +#: includes/class-wcs-user-change-status-handler.php:67 +msgctxt "order note left on subscription after user action" +msgid "Subscription put on hold by the subscriber from their account page." +msgstr "Abonnement mis en attente par l’abonné sur sa page de compte." + +#: includes/class-wcs-user-change-status-handler.php:58 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been reactivated." +msgstr "Votre abonnement a été réactivé." + +#: includes/class-wcs-user-change-status-handler.php:57 +msgctxt "order note left on subscription after user action" +msgid "Subscription reactivated by the subscriber from their account page." +msgstr "Abonnement réactivé par l’abonné sur sa page de compte." + +#: includes/class-wcs-cart-renewal.php:676 +msgctxt "" +"Used in WooCommerce by removed item notification: \"_All linked subscription " +"items were_ removed. Undo?\" Filter for item title." +msgid "All linked subscription items were" +msgstr "Tous les articles d’abonnement liés étaient" + +#: includes/class-wc-subscriptions-synchroniser.php:319 +#: templates/admin/deprecated/html-variation-synchronisation.php:36 +#: templates/admin/html-variation-synchronisation.php:42 +msgctxt "input field placeholder for day field for annual subscriptions" +msgid "Day" +msgstr "Jour" + +#: includes/class-wc-subscriptions-switcher.php:433 +#: includes/class-wc-subscriptions-synchroniser.php:236 +msgctxt "when to prorate first payment / subscription length" +msgid "For All Subscription Products" +msgstr "Pour tous les produits d’abonnement" + +#. translators: $1: opening link tag, $2: order number, $3: closing link tag +#: includes/class-wc-subscriptions-order.php:1056 +msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s." +msgstr "Abonnement annulé pour la commande remboursée %1$sn°%2$s%3$s." + +#: includes/class-wc-subscriptions-manager.php:1079 +msgctxt "Subscription status" +msgid "On-hold" +msgstr "En attente" + +#: includes/class-wc-subscriptions-manager.php:1075 +msgctxt "Subscription status" +msgid "Failed" +msgstr "Échec" + +#: includes/class-wc-subscriptions-manager.php:87 +#: includes/class-wc-subscriptions-manager.php:1918 +#: includes/class-wc-subscriptions-manager.php:1936 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Subscription renewal payment due:" +msgstr "Paiement de renouvellement d’abonnement à régler :" + +#. translators: 1$: coupon code that is being removed +#: includes/class-wc-subscriptions-coupon.php:474 +msgid "Sorry, the \"%1$s\" coupon is only valid for renewals." +msgstr "" +"Désolé, le code promo « %1$s » n’est valide que pour les renouvellements." + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:213 +msgid "Error %d: Unable to add tax to subscription. Please try again." +msgstr "" +"Erreur %d : Impossible d’ajouter la TVA à l’abonnement. Veuillez réessayer." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:709 +#: includes/class-wc-subscriptions-change-payment-gateway.php:747 +msgctxt "the page title of the change payment method form" +msgid "Change payment method" +msgstr "Modifier le moyen de paiement" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:277 +msgctxt "label on button, imperative" +msgid "Change payment" +msgstr "Modifier le paiement" + +#. translators: placeholder is the formatted total to be paid for the +#. subscription wrapped in tags +#: templates/checkout/subscription-receipt.php:30 +msgid "Total: %s" +msgstr "Total : %s" + +#: includes/api/legacy/class-wc-api-subscriptions.php:613 +msgctxt "API response confirming order note deleted from a subscription" +msgid "Permanently deleted subscription note" +msgstr "Note d’abonnement supprimée définitivement" + +#. translators: placeholder is error message +#: includes/api/legacy/class-wc-api-subscriptions.php:276 +msgctxt "API error message when editing the order failed" +msgid "Edit subscription failed with error: %s" +msgstr "La modification de l’abonnement a échoué avec une erreur : %s" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:21 +#: templates/myaccount/my-subscriptions.php:24 +#: templates/myaccount/related-orders.php:25 +#: templates/myaccount/related-subscriptions.php:24 +#: templates/myaccount/subscription-totals-table.php:22 +msgctxt "table heading" +msgid "Total" +msgstr "Total" + +#. translators: $1: is opening link, $2: is subscription order number, $3: is +#. closing link tag, $4: is user's name +#: includes/admin/class-wcs-admin-post-types.php:565 +msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)" +msgid "%1$s#%2$s%3$s for %4$s" +msgstr "%1$sn°%2$s%3$s pour %4$s" + +#. translators: placeholder is customer's billing phone number +#: includes/admin/class-wcs-admin-post-types.php:537 +msgid "Tel: %s" +msgstr "Tél : %s" + +#. translators: placeholder is customer's billing email +#: includes/admin/class-wcs-admin-post-types.php:532 +msgid "Email: %s" +msgstr "E-mail : %s" + +#: includes/admin/class-wcs-admin-post-types.php:431 +msgctxt "number of orders linked to a subscription" +msgid "Orders" +msgstr "Commandes" + +#: includes/admin/class-wcs-admin-post-types.php:427 +msgid "Trial End" +msgstr "Fin de l’essai" + +#: includes/admin/class-wcs-admin-post-types.php:424 +msgid "Items" +msgstr "Articles" + +#: includes/admin/class-wcs-admin-post-types.php:335 +msgctxt "Used in order note. Reason why status changed." +msgid "Subscription status changed by bulk edit:" +msgstr "État d’abonnement modifié en lot :" + +#: includes/admin/class-wcs-admin-post-types.php:260 +#: includes/admin/class-wcs-admin-post-types.php:473 +#: includes/class-wc-subscriptions-manager.php:1854 +#: includes/wcs-user-functions.php:354 +#: templates/myaccount/related-orders.php:78 +msgctxt "an action on a subscription" +msgid "Cancel" +msgstr "Annuler" + +#: includes/admin/class-wcs-admin-post-types.php:258 +msgctxt "an action on a subscription" +msgid "Activate" +msgstr "Activer" + +#: includes/admin/class-wc-subscriptions-admin.php:1729 +#: includes/admin/class-wcs-admin-system-status.php:107 +msgctxt "Live or Staging, Label on WooCommerce -> System Status page" +msgid "Subscriptions Mode" +msgstr "Mode d’abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:864 +msgid "" +"Warning: Deleting a user will also delete the user's subscriptions. The " +"user's orders will remain but be reassigned to the 'Guest' user.\n" +"\n" +"Do you want to continue to delete this user and any associated subscriptions?" +msgstr "" +"Attention : supprimer un utilisateur supprimera également les abonnements de " +"cet utilisateur. Les commandes de l’utilisateur resteront mais seront " +"réaffectées à l’utilisateur « Invité ».\n" +"\n" +"Voulez-vous continuer et supprimer cet utilisateur et les abonnements " +"associés ?" + +#. translators: placeholder is trial period validation message if passed an +#. invalid value (e.g. "Trial period can not exceed 4 weeks") +#: templates/admin/deprecated/html-variation-price.php:118 +#: templates/admin/html-variation-price.php:27 +msgctxt "Trial period dropdown's description in pricing fields" +msgid "" +"An optional period of time to wait before charging the first recurring " +"payment. Any sign up fee will still be charged at the outset of the " +"subscription. %s" +msgstr "" +"Une période d’attente facultative avant de facturer le premier paiement " +"récurrent. Les frais d’inscription seront toujours facturés au début de " +"l’abonnement. %s" + +#. Description of the plugin +msgid "" +"Sell products and services with recurring payments in your WooCommerce Store." +msgstr "" +"Vendez des produits et des services avec des paiements récurrents dans votre " +"boutique WooCommerce." + +#. Plugin Name of the plugin +#: includes/privacy/class-wcs-privacy.php:40 +msgid "WooCommerce Subscriptions" +msgstr "Abonnements WooCommerce" + +#. translators: opening/closing tags - linked to ticket form. +#: woocommerce-subscriptions.php:1251 +msgid "" +"Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer " +"immediately. If you need assistance, after upgrading to Subscriptions v2.0, " +"please %1$sopen a support ticket%2$s." +msgstr "" +"Veuillez mettre à niveau l’extension WooCommerce Subscriptions vers la " +"version 2.0 ou plus récente immédiatement. Si vous avez besoin d’aide, après " +"la mise à niveau vers Subscriptions v2.0, veuillez %1$souvrir un ticket " +"d’assistance%2$s." + +#. translators: placeholder is Subscriptions version number. +#: woocommerce-subscriptions.php:1249 +msgid "" +"Warning! You are running version %s of WooCommerce Subscriptions plugin code " +"but your database has been upgraded to Subscriptions version 2.0. This will " +"cause major problems on your store." +msgstr "" +"Attention ! Vous exécutez la version %s du code d’extension WooCommerce " +"Subscriptions, mais votre base de données a été mise à niveau vers " +"Subscriptions version 2.0. Cela entraînera des problèmes majeurs sur votre " +"boutique." + +#. translators: placeholders are opening and closing tags. Leads to docs on +#. version 2 +#: woocommerce-subscriptions.php:1233 +msgid "" +"Warning! Version 2.0 is a major update to the WooCommerce Subscriptions " +"extension. Before updating, please create a backup, update all WooCommerce " +"extensions and test all plugins, custom code and payment gateways with " +"version 2.0 on a staging site. %1$sLearn more about the changes in version 2." +"0 »%2$s" +msgstr "" +"Attention ! La version 2.0 est une mise à jour majeure de l’extension " +"WooCommerce Subscriptions. Avant la mise à jour, veuillez créer une " +"sauvegarde, mettre à jour toutes les extensions WooCommerce et tester toutes " +"les extensions, le code personnalisé et les passerelles de paiement avec la " +"version 2.0 sur un site de préproduction. %1$sEn savoir plus sur les " +"modifications dans la version 2.0 »%2$s" + +#: woocommerce-subscriptions.php:1150 +msgid "Support" +msgstr "Forums de support" + +#: includes/upgrades/templates/wcs-about-2-0.php:36 +#: woocommerce-subscriptions.php:1149 +msgctxt "short for documents" +msgid "Docs" +msgstr "Documentations" + +#: woocommerce-subscriptions.php:944 +msgid "Enable automatic payments" +msgstr "Activer les paiements automatiques" + +#: woocommerce-subscriptions.php:939 +msgid "Quit nagging me (but don't enable automatic payments)" +msgstr "Ne plus me rappeler (mais ne pas activer les paiements automatiques)" + +#: woocommerce-subscriptions.php:761 +msgid "Variable Subscription" +msgstr "Abonnement variable" + +#. translators: 1$-2$: opening and closing tags, 3$: minimum supported +#. WooCommerce version, 4$-5$: opening and closing link tags, leads to plugin +#. admin +#: woocommerce-subscriptions.php:730 +msgid "" +"%1$sWooCommerce Subscriptions is inactive.%2$s This version of Subscriptions " +"requires WooCommerce %3$s or newer. Please %4$supdate WooCommerce to version " +"%3$s or newer »%5$s" +msgstr "" +"%1$sWooCommerce Subscriptions est inactif.%2$s Cette version de " +"Subscriptions requiert %3$s ou version plus récente. Veuillez %4$smettre à " +"jour WooCommerce vers la version %3$s ou plus récente »%5$s" + +#. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, +#. takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, +#. leads to plugins.php in admin +#: woocommerce-subscriptions.php:727 +msgid "" +"%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce " +"plugin%4$s must be active for WooCommerce Subscriptions to work. Please " +"%5$sinstall & activate WooCommerce »%6$s" +msgstr "" +"%1$sWooCommerce Subscriptions est inactif.%2$s L’%3$sextension " +"WooCommerce%4$s doit être active pour que WooCommerce Subscriptions " +"fonctionne. Veuillez %5$sinstaller et activer WooCommerce »%6$s" + +#. translators: placeholder is a number, numbers ending in 3 +#: woocommerce-subscriptions.php:688 +msgid "%srd" +msgstr "%se" + +#. translators: placeholder is a number, numbers ending in 2 +#: woocommerce-subscriptions.php:684 +msgid "%snd" +msgstr "%se" + +#. translators: placeholder is a number, numbers ending in 1 +#: woocommerce-subscriptions.php:680 +msgid "%sst" +msgstr "%ser" + +#. translators: placeholder is a number, this is for the teens +#. translators: placeholder is a number, numbers ending in 4-9, 0 +#: woocommerce-subscriptions.php:675 woocommerce-subscriptions.php:692 +msgid "%sth" +msgstr "%se" + +#: includes/class-wc-subscriptions-cart-validator.php:68 +#: woocommerce-subscriptions.php:535 +msgid "" +"A subscription has been removed from your cart. Products and subscriptions " +"can not be purchased at the same time." +msgstr "" +"Un abonnement a été supprimé de votre panier. Les produits et les " +"abonnements ne peuvent pas être achetés en même temps." + +#: includes/class-wc-subscriptions-cart-validator.php:62 +#: woocommerce-subscriptions.php:529 +msgid "" +"A subscription has been removed from your cart. Due to payment gateway " +"restrictions, different subscription products can not be purchased at the " +"same time." +msgstr "" +"Un abonnement a été supprimé de votre panier. En raison des restrictions de " +"la passerelle de paiement, différents produits d’abonnement ne peuvent pas " +"être achetés en même temps." + +#: includes/class-wc-subscriptions-cart-validator.php:56 +#: woocommerce-subscriptions.php:523 +msgid "" +"A subscription renewal has been removed from your cart. Multiple " +"subscriptions can not be purchased at the same time." +msgstr "" +"Un renouvellement d’abonnement a été supprimé de votre panier. Plusieurs " +"abonnements ne peuvent pas être achetés en même temps." + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:353 +msgctxt "post status label including post count" +msgid "Pending Cancellation (%s)" +msgid_plural "Pending Cancellation (%s)" +msgstr[0] "Annulation en attente (%s)" +msgstr[1] "Annulation en attente (%s)" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:351 +msgctxt "post status label including post count" +msgid "Expired (%s)" +msgid_plural "Expired (%s)" +msgstr[0] "Expiré (%s)" +msgstr[1] "Expiré (%s)" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:349 +msgctxt "post status label including post count" +msgid "Switched (%s)" +msgid_plural "Switched (%s)" +msgstr[0] "Changé (%s)" +msgstr[1] "Changé (%s)" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:347 +msgctxt "post status label including post count" +msgid "Active (%s)" +msgid_plural "Active (%s)" +msgstr[0] "Actif (%s)" +msgstr[1] "Actif (%s)" + +#. translators: placeholders are opening and closing link tags +#: woocommerce-subscriptions.php:332 +msgid "%1$sAdd a subscription product »%2$s" +msgstr "%1$sAjouter un produit d’abonnement »%2$s" + +#. translators: placeholders are opening and closing link tags +#: woocommerce-subscriptions.php:330 +msgid "%1$sLearn more about managing subscriptions »%2$s" +msgstr "%1$sEn savoir plus sur la gestion des abonnements »%2$s" + +#: woocommerce-subscriptions.php:328 +msgid "" +"Subscriptions will appear here for you to view and manage once purchased by " +"a customer." +msgstr "" +"Les abonnements apparaîtront ici pour que vous puissiez les consulter et les " +"gérer une fois achetés par un client." + +#: woocommerce-subscriptions.php:326 +msgid "No Subscriptions found" +msgstr "Aucun abonnement trouvé" + +#: woocommerce-subscriptions.php:281 +msgid "This is where subscriptions are stored." +msgstr "Il s’agit de l’emplacement de stockage des abonnements." + +#: woocommerce-subscriptions.php:278 +msgctxt "custom post type setting" +msgid "Parent Subscriptions" +msgstr "Abonnements parents" + +#: woocommerce-subscriptions.php:277 +msgctxt "custom post type setting" +msgid "No Subscriptions found in trash" +msgstr "Aucun abonnement trouvé dans la corbeille" + +#: woocommerce-subscriptions.php:273 woocommerce-subscriptions.php:274 +msgctxt "custom post type setting" +msgid "View Subscription" +msgstr "Afficher l’abonnement" + +#: woocommerce-subscriptions.php:272 +msgctxt "custom post type setting" +msgid "New Subscription" +msgstr "Nouvel abonnement" + +#: woocommerce-subscriptions.php:271 +msgctxt "custom post type setting" +msgid "Edit Subscription" +msgstr "Modifier l’abonnement" + +#: woocommerce-subscriptions.php:270 +msgctxt "custom post type setting" +msgid "Edit" +msgstr "Modifier" + +#: woocommerce-subscriptions.php:269 +msgctxt "custom post type setting" +msgid "Add New Subscription" +msgstr "Ajouter un nouvel abonnement" + +#: woocommerce-subscriptions.php:268 +msgctxt "custom post type setting" +msgid "Add Subscription" +msgstr "Ajouter un abonnement" + +#: wcs-functions.php:345 +msgid "Date type can not be an empty string." +msgstr "Le type de date ne peut pas être une chaîne vide." + +#: wcs-functions.php:343 +msgid "Date type is not a string." +msgstr "Le type de date n’est pas une chaîne." + +#: wcs-functions.php:254 +msgid "Can not get status name. Status is not a string." +msgstr "Impossible d’obtenir le nom de l’état. L’état n’est pas une chaîne." + +#: wcs-functions.php:238 +msgctxt "Subscription status" +msgid "Pending Cancellation" +msgstr "Annulation en attente" + +#: includes/class-wc-subscriptions-manager.php:1069 wcs-functions.php:237 +msgctxt "Subscription status" +msgid "Expired" +msgstr "Expiré" + +#: includes/class-wc-subscriptions-switcher.php:2704 wcs-functions.php:236 +msgctxt "Subscription status" +msgid "Switched" +msgstr "Changé" + +#: includes/class-wc-subscriptions-manager.php:1066 wcs-functions.php:235 +msgctxt "Subscription status" +msgid "Cancelled" +msgstr "Annulé" + +#: wcs-functions.php:234 +msgctxt "Subscription status" +msgid "On hold" +msgstr "En attente" + +#: includes/class-wc-subscriptions-manager.php:1063 wcs-functions.php:233 +msgctxt "Subscription status" +msgid "Active" +msgstr "Actif" + +#: includes/class-wc-subscriptions-manager.php:1072 wcs-functions.php:232 +msgctxt "Subscription status" +msgid "Pending" +msgstr "En attente" + +#: tests/unit/wcs_test_wcs_functions.php:833 +msgctxt "table column header" +msgid "Big Bang" +msgstr "Big Bang" + +#: templates/single-product/add-to-cart/subscription.php:32 +#: templates/single-product/add-to-cart/variable-subscription.php:30 +msgid "You have an active subscription to this product already." +msgstr "Vous avez déjà un abonnement actif à ce produit." + +#: includes/privacy/class-wcs-privacy-exporters.php:84 wcs-functions.php:283 +msgid "Shipping Address" +msgstr "Adresse de livraison" + +#: includes/privacy/class-wcs-privacy-exporters.php:83 wcs-functions.php:284 +msgid "Billing Address" +msgstr "Adresse de facturation" + +#: includes/admin/meta-boxes/views/html-retries-table.php:31 +msgid "Email" +msgstr "Adresse de messagerie" + +#. translators: placeholder is price string, denotes tax included in cart/order +#. total +#: includes/wcs-cart-functions.php:320 +msgctxt "includes tax" +msgid "(includes %s)" +msgstr "(inclut %s)" + +#: templates/myaccount/subscription-totals-table.php:35 +msgid "Are you sure you want remove this item from your subscription?" +msgstr "Voulez-vous vraiment supprimer cet article de votre abonnement ?" + +#: templates/myaccount/subscription-totals.php:23 +msgid "Subscription totals" +msgstr "Totaux des abonnements" + +#: templates/myaccount/subscription-details.php:100 +msgctxt "date on subscription updates list. Will be localized" +msgid "l jS \\o\\f F Y, h:ia" +msgstr "\\f F Y, h:ial jS \\o" + +#: templates/myaccount/subscription-details.php:94 +msgid "Subscription updates" +msgstr "Mises à jour des abonnements" + +#: templates/myaccount/subscription-details.php:81 +msgid "Actions" +msgstr "Actions" + +#: templates/myaccount/subscription-details.php:28 +msgctxt "customer subscription table header" +msgid "Trial end date" +msgstr "Date de fin d’essai" + +#: templates/myaccount/subscription-details.php:27 +msgctxt "customer subscription table header" +msgid "End date" +msgstr "Date de fin" + +#: templates/myaccount/subscription-details.php:26 +msgctxt "customer subscription table header" +msgid "Next payment date" +msgstr "Date du paiement suivant" + +#: templates/myaccount/subscription-details.php:25 +msgctxt "customer subscription table header" +msgid "Last order date" +msgstr "Date de la dernière commande" + +#: includes/class-wcs-template-loader.php:28 +msgid "My Account" +msgstr "Mon compte :" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:250 +#: includes/class-wcs-template-loader.php:28 +#: includes/wcs-helper-functions.php:286 +msgid "Invalid Subscription." +msgstr "Abonnement non valide." + +#: templates/myaccount/related-subscriptions.php:15 +msgid "Related subscriptions" +msgstr "Abonnements liés" + +#: templates/myaccount/my-subscriptions.php:50 +#: templates/myaccount/related-orders.php:84 +#: templates/myaccount/related-subscriptions.php:46 +msgctxt "view a subscription" +msgid "View" +msgstr "Voir" + +#: templates/myaccount/related-orders.php:65 +msgctxt "pay for a subscription" +msgid "Pay" +msgstr "Payer" + +#: templates/myaccount/related-orders.php:22 +msgid "Order" +msgstr "Ordre" + +#: includes/admin/class-wcs-admin-meta-boxes.php:79 +#: includes/admin/class-wcs-admin-meta-boxes.php:83 +msgid "Related Orders" +msgstr "Commandes similaires" + +#. translators: placeholder is the display name of a payment gateway a +#. subscription was paid by +#. translators: %s: payment method. +#: includes/admin/class-wcs-admin-post-types.php:609 +#: includes/class-wc-subscription.php:2025 +msgid "Via %s" +msgstr "Via %s" + +#: templates/myaccount/my-subscriptions.php:33 +#: templates/myaccount/related-subscriptions.php:31 +msgid "ID" +msgstr "ID" + +#: includes/admin/class-wcs-admin-post-types.php:428 +msgid "Next Payment" +msgstr "Paiement suivant" + +#: includes/admin/class-wcs-admin-post-types.php:430 +msgid "End Date" +msgstr "Date de fin" + +#: includes/admin/class-wcs-admin-post-types.php:426 +msgid "Start Date" +msgstr "Date de début" + +#: includes/class-wcs-query.php:296 +msgid "View subscription" +msgstr "Afficher l’abonnement" + +#: templates/emails/plain/subscription-info.php:20 +#: templates/emails/subscription-info.php:21 +msgid "Subscription information" +msgstr "Informations sur l’abonnement" + +#. translators: placeholder is subscription's view url +#: templates/emails/plain/customer-completed-switch-order.php:35 +msgid "View your subscription: %s" +msgstr "Afficher votre abonnement : %s" + +#. translators: placeholder is order's view url +#: templates/emails/plain/customer-completed-switch-order.php:24 +msgid "View your order: %s" +msgstr "Afficher votre commande : %s" + +#. translators: placeholder is localised date string +#: templates/emails/plain/cancelled-subscription.php:39 +msgid "End of Prepaid Term: %s" +msgstr "Fin du terme prépayé : %s" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/cancelled-subscription.php:16 +#: templates/emails/plain/cancelled-subscription.php:16 +msgid "" +"A subscription belonging to %1$s has been cancelled. Their subscription's " +"details are as follows:" +msgstr "" +"Un abonnement appartenant à %1$s a été annulé. Les détails de son abonnement " +"sont les suivants :" + +#. translators: placeholder is the subscription order number wrapped in +#. tags +#: templates/checkout/subscription-receipt.php:18 +#: templates/emails/plain/email-order-details.php:19 +msgid "Subscription Number: %s" +msgstr "Numéro d’abonnement : %s" + +#: templates/emails/plain/email-order-details.php:17 +msgid "Order date: %s" +msgstr "Date de la commande : %s" + +#: templates/emails/plain/email-order-details.php:16 +msgid "Order number: %s" +msgstr "Numéro de commande : %s" + +#: templates/emails/customer-renewal-invoice.php:24 +#: templates/emails/customer-renewal-invoice.php:33 +msgid "Pay Now »" +msgstr "Payer maintenant »" + +#: templates/emails/customer-completed-switch-order.php:18 +#: templates/emails/plain/customer-completed-switch-order.php:17 +msgid "" +"You have successfully changed your subscription items. Your new order and " +"subscription details are shown below for your reference:" +msgstr "" +"Vous avez modifié avec succès vos articles d’abonnement. Les détails de " +"votre nouvelle commande et de votre abonnement sont indiqués ci-dessous pour " +"votre référence :" + +#: includes/admin/class-wcs-admin-post-types.php:423 +#: templates/emails/cancelled-subscription.php:21 +#: templates/emails/expired-subscription.php:21 +#: templates/emails/on-hold-subscription.php:21 +#: templates/myaccount/my-subscriptions.php:21 +#: templates/myaccount/related-subscriptions.php:21 +#: woocommerce-subscriptions.php:267 +msgid "Subscription" +msgstr "Abonnement" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/expired-subscription.php:16 +#: templates/emails/plain/expired-subscription.php:16 +msgid "" +"A subscription belonging to %1$s has expired. Their subscription's details " +"are as follows:" +msgstr "" +"Un abonnement appartenant à %1$s a expiré. Les détails de son abonnement " +"sont les suivants :" + +#: templates/emails/admin-new-switch-order.php:28 +#: templates/emails/customer-completed-switch-order.php:26 +msgid "New subscription details" +msgstr "Détails du nouvel abonnement" + +#: templates/emails/admin-new-switch-order.php:20 +msgid "Switch Order Details" +msgstr "Détails de la commande de changement" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:43 +msgid "Customer Totals" +msgstr "Totaux des clients" + +#: includes/privacy/class-wcs-privacy-exporters.php:79 +msgid "Recurring Total" +msgstr "" + +#. translators: %s: shipping method label. +#: includes/wcs-cart-functions.php:97 includes/wcs-cart-functions.php:102 +msgid "Shipping via %s" +msgstr "Livraison via %s" + +#: templates/checkout/recurring-totals.php:31 +#: templates/checkout/recurring-totals.php:32 +msgid "Subtotal" +msgstr "Sous-total" + +#: templates/checkout/recurring-totals.php:151 +#: templates/checkout/recurring-totals.php:152 +msgid "Recurring total" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:82 +msgid "" +"Sorry, it seems no payment gateways support changing the recurring payment " +"method. Please contact us if you require assistance or to make alternate " +"arrangements." +msgstr "" +"Désolé, il semble qu’aucune passerelle de paiement ne prenne en charge la " +"modification du moyen de paiement récurrent. Veuillez nous contacter si vous " +"avez besoin d’aide ou si vous désirez mettre en place une alternative." + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:21 +msgid "Products" +msgstr "Produits" + +#: templates/admin/deprecated/order-tax-html.php:21 +msgid "Shipping Tax:" +msgstr "Taxe d’expédition :" + +#: templates/admin/deprecated/order-tax-html.php:17 +msgid "Recurring Sales Tax:" +msgstr "Taxes de vente récurrentes :" + +#: templates/admin/deprecated/order-shipping-html.php:34 +#: templates/admin/deprecated/order-shipping-html.php:36 +msgid "Other" +msgstr "Autre" + +#: templates/admin/deprecated/order-shipping-html.php:13 +msgid "Shipping Method" +msgstr "Méthode d’expédition" + +#: templates/admin/deprecated/order-shipping-html.php:8 +msgid "Label" +msgstr "Nom" + +#: templates/admin/html-variation-price.php:49 +msgid "Billing interval:" +msgstr "Intervalle de facturation :" + +#. translators: %s: currency symbol. +#. translators: placeholder is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:301 +#: templates/admin/html-variation-price.php:44 +msgid "Subscription price (%s)" +msgstr "Prix de l’abonnement (%s)" + +#: includes/admin/class-wc-subscriptions-admin.php:354 +#: templates/admin/html-variation-price.php:25 +msgid "Free trial" +msgstr "Essai gratuit" + +#. translators: %s is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:340 +#: templates/admin/html-variation-price.php:20 +msgid "Sign-up fee (%s)" +msgstr "Frais d’inscription (%s)" + +#: templates/admin/deprecated/html-variation-price.php:105 +msgctxt "example number of days / weeks / months" +msgid "e.g. 3" +msgstr "par ex. 3" + +#: includes/wcs-user-functions.php:345 +#: templates/single-product/add-to-cart/subscription.php:30 +#: templates/single-product/add-to-cart/variable-subscription.php:28 +msgid "Resubscribe" +msgstr "Se réabonner" + +#: includes/wcs-time-functions.php:210 +msgctxt "no trial period" +msgid "no" +msgstr "non" + +#: includes/wcs-time-functions.php:159 +msgctxt "period interval (eg \"$10 _every_ 2 weeks\")" +msgid "every" +msgstr "chaque" + +#: includes/wcs-order-functions.php:523 +msgid "Invalid data. No valid item id was passed in." +msgstr "" +"Données non valides. Aucun identifiant d’article valide n’a été transmis." + +#: includes/wcs-order-functions.php:519 +msgid "Invalid data. No valid subscription / order was passed in." +msgstr "" +"Données non valides. Aucun abonnement/commande valide n’a été transmis." + +#. translators: placeholder is an order type. +#: includes/wcs-order-functions.php:329 +msgid "\"%s\" is not a valid new order type." +msgstr "« %s » n’est pas un type de nouvelle commande valide." + +#: includes/wcs-order-functions.php:324 +msgid "$type passed to the function was not a string." +msgstr "$type transmis à la fonction n’était pas une chaîne." + +#. translators: placeholder is a date. +#: includes/wcs-order-functions.php:305 +msgid "Resubscribe Order – %s" +msgstr "Commande de réabonnement – %s" + +#. translators: placeholder is a date. +#: includes/wcs-order-functions.php:301 +msgid "Subscription Renewal Order – %s" +msgstr "Commande de renouvellement d’abonnement – %s" + +#. translators: placeholders are strftime() strings. +#. translators: Order date parsed by strftime +#: includes/wcs-order-functions.php:296 wcs-functions.php:161 +msgctxt "" +"Used in subscription post title. \"Subscription renewal order - \"" +msgid "%b %d, %Y @ %I:%M %p" +msgstr "%b %d, %Y à %I:%M %p" + +#. translators: minute placeholder for time input, javascript format +#: includes/wcs-helper-functions.php:48 +msgid "MM" +msgstr "MM" + +#. translators: hour placeholder for time input, javascript format +#: includes/wcs-helper-functions.php:45 +msgid "HH" +msgstr "HH" + +#. translators: date placeholder for input, javascript format +#: includes/wcs-helper-functions.php:40 +msgid "YYYY-MM-DD" +msgstr "AAAA-MM-JJ" + +#. translators: 1$: trial length (e.g. "3 weeks"), 2$: subscription string +#. (e.g. "$10 up front then $5 on March 23rd every 3rd year") +#: includes/wcs-formatting-functions.php:219 +msgid "%1$s free trial then %2$s" +msgstr "%1$s essai gratuit puis %2$s" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March +#. 23rd every 3rd year"), 2$: trial length (e.g. "3 weeks") +#: includes/wcs-formatting-functions.php:216 +msgid "%1$s after %2$s free trial" +msgstr "%1$s après l’essai gratuit de %2$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: subscription period (e.g. "month" or "3 months") +#: includes/wcs-formatting-functions.php:194 +msgid "%1$s %2$s then %3$s / %4$s" +msgid_plural "%1$s %2$s then %3$s every %4$s" +msgstr[0] "%1$s %2$s puis %3$s / %4$s" +msgstr[1] "%1$s %2$s puis %3$s chaque %4$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g. +#. "23rd"), 6$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:184 +msgid "%1$s %2$s then %3$s on %4$s %5$s every %6$s year" +msgstr "%1$s %2$s puis %3$s le %4$s %5$s chaque %6$s année" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month +#. (e.g. "23rd") +#: includes/wcs-formatting-functions.php:175 +msgid "%1$s %2$s then %3$s on %4$s %5$s each year" +msgstr "%1$s %2$s puis %3$s le %4$s %5$s chaque année" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g. +#. "3rd") +#: includes/wcs-formatting-functions.php:157 +msgid "%1$s %2$s then %3$s on the %4$s day of every %5$s month" +msgstr "%1$s %2$s puis %3$s le %4$s jour de chaque %5$s mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:154 +msgid "%1$s %2$s then %3$s on the last day of every %4$s month" +msgstr "%1$s %2$s puis %3$s le dernier jour de chaque %4$s mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up +#. front then $40 on the 23rd of each month") +#: includes/wcs-formatting-functions.php:138 +msgid "%1$s %2$s then %3$s on the %4$s of each month" +msgstr "%1$s %2$s puis %3$s le %4$s de chaque mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount; (e.g. "$10 up front then $30 on the last day of each +#. month") +#: includes/wcs-formatting-functions.php:135 +msgid "%1$s %2$s then %3$s on the last day of each month" +msgstr "%1$s %2$s puis %3$s le dernier jour de chaque mois" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front" ), +#. 3$: recurring amount, 4$: interval (e.g. "2nd week"), 5$: day of the week +#. (e.g. "Thursday"); (e.g. "$10 up front, then $20 every 2nd week on +#. Wednesday") +#: includes/wcs-formatting-functions.php:122 +msgid "%1$s %2$s then %3$s every %4$s on %5$s" +msgstr "%1$s %2$s puis %3$s chaque %4$s le %5$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount string, 4$: payment day of the week (e.g. "$15 up +#. front, then $10 every Wednesday") +#: includes/wcs-formatting-functions.php:113 +msgid "%1$s %2$s then %3$s every %4$s" +msgstr "%1$s %2$s puis %3$s chaque %4$s" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), +#. 3$: recurring amount string (e.g. "£10 / month" ) +#: includes/wcs-formatting-functions.php:99 +msgid "%1$s %2$s then %3$s" +msgstr "%1$s %2$s puis %3$s" + +#: includes/wcs-formatting-functions.php:41 +msgctxt "initial payment on a subscription" +msgid "up front" +msgstr "à l’avance" + +#. translators: placeholder is either subscription key or a subscription id, +#. or, failing that, empty (e.g. "145_21" or "145") +#: includes/wcs-deprecated-functions.php:180 +msgid "" +"Could not get subscription. Most likely the subscription key does not refer " +"to a subscription. The key was: \"%s\"." +msgstr "" +"Impossible d’obtenir l’abonnement. Très probablement, la clé d’abonnement ne " +"fait pas référence à un abonnement. La clé était : « %s »." + +#. translators: placeholder is a date +#: includes/wcs-cart-functions.php:389 +#: tests/unit/wcs_test_wcs_cart_functions.php:225 +msgid "First renewal: %s" +msgstr "Premier renouvellement : %s" + +#: includes/wcs-cart-functions.php:282 +msgid "Free shipping coupon" +msgstr "Code promo livraison gratuite" + +#: includes/wcs-cart-functions.php:227 +msgctxt "shipping method price" +msgid "Free" +msgstr "Gratuit" + +#: includes/upgrades/templates/wcs-upgrade.php:72 +msgid "" +"There was an error with the update. Please refresh the page and try again." +msgstr "" +"Une erreur est survenue lors de la mise à jour. Veuillez rafraîchir la page " +"et réessayer." + +#: includes/upgrades/templates/wcs-upgrade.php:71 +msgid "Update Error" +msgstr "Erreur de mise à jour" + +#. translators: $1: placeholder is number of weeks, 2$: path to the file +#: includes/upgrades/templates/wcs-upgrade.php:66 +msgid "" +"To record the progress of the update a new log file was created. This file " +"will be automatically deleted in %1$d weeks. If you would like to delete it " +"sooner, you can find it here: %2$s" +msgstr "" +"Pour enregistrer la progression de la mise à jour, un nouveau fichier " +"journal a été créé. Ce fichier sera supprimé automatiquement dans " +"%1$d semaines. Si vous voulez le supprimer plus tôt, vous pouvez le trouver " +"ici : %2$s" + +#: includes/upgrades/templates/wcs-upgrade.php:63 +msgid "Continue" +msgstr "Continuer" + +#: includes/upgrades/templates/wcs-upgrade.php:62 +msgid "Your database has been updated successfully!" +msgstr "Votre base de données a été mise à jour avec succès !" + +#: includes/upgrades/templates/wcs-upgrade.php:61 +msgid "Update Complete" +msgstr "Mise à jour terminée" + +#: includes/upgrades/templates/wcs-upgrade.php:53 +msgid "" +"Remember, although the update process may take a while, customers and other " +"non-administrative users can browse and purchase from your store without " +"interruption while the update is in progress." +msgstr "" +"Rappelez-vous que, bien que le processus de mise à jour puisse prendre un " +"certain temps, les clients et autres utilisateurs non administratifs peuvent " +"parcourir et acheter dans votre boutique sans interruption pendant que la " +"mise à jour est en cours." + +#: includes/upgrades/templates/wcs-upgrade.php:51 +msgid "" +"Please keep this page open until the update process completes. No need to " +"refresh or restart the process." +msgstr "" +"Veuillez garder cette page ouverte jusqu’à la fin du processus de mise à " +"jour. Pas besoin de rafraîchir ou de redémarrer le processus." + +#: includes/upgrades/templates/wcs-upgrade.php:50 +msgid "" +"This page will display the results of the process as each batch of " +"subscriptions is updated." +msgstr "" +"Cette page affichera les résultats du processus au fur et à mesure que " +"chaque lot d’abonnements est mis à jour." + +#: includes/upgrades/templates/wcs-upgrade.php:49 +msgid "Update in Progress" +msgstr "Mise à jour en cours" + +#: includes/upgrades/templates/wcs-upgrade.php:45 +msgctxt "text on submit button" +msgid "Update Database" +msgstr "Mettre à jour la base de données" + +#: includes/upgrades/templates/wcs-upgrade.php:43 +msgid "" +"Customers and other non-administrative users can browse and purchase from " +"your store without interruption while the update is in progress." +msgstr "" +"Les clients et autres utilisateurs non administratifs peuvent parcourir et " +"acheter dans votre boutique sans interruption pendant que la mise à jour est " +"en cours." + +#: includes/upgrades/templates/wcs-upgrade.php:41 +msgid "The update process may take a little while, so please be patient." +msgstr "" +"Le processus de mise à jour peut prendre un peu de temps, alors soyez " +"patient." + +#. translators: 1$: number of subscriptions on site, 2$, lower estimate +#. (minutes), 3$: upper estimate +#: includes/upgrades/templates/wcs-upgrade.php:38 +msgid "" +"The full update process for the %1$d subscriptions on your site will take " +"between %2$d and %3$d minutes." +msgstr "" +"Le processus complet de mise à jour des %1$d abonnements sur votre site " +"prendra entre %2$d et %3$d minutes. " + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-upgrade.php:33 +msgid "" +"Before we send you on your way, we need to update your database to the " +"newest version. If you do not have a recent backup of your site, %snow is " +"the time to create one%s." +msgstr "" +"Avant de vous laisser, nous devons mettre à jour votre base de données avec " +"la dernière version. Si vous ne disposez pas d’une sauvegarde récente de " +"votre site, %sil est maintenant temps d’en créer une%s." + +#: includes/upgrades/templates/wcs-upgrade.php:30 +msgid "The WooCommerce Subscriptions plugin has been updated!" +msgstr "L’extension WooCommerce Subscriptions a été mise à jour !" + +#: includes/upgrades/templates/wcs-upgrade.php:29 +msgid "Database Update Required" +msgstr "Mise à jour de base de données obligatoire" + +#: includes/upgrades/templates/wcs-upgrade.php:19 +msgid "WooCommerce Subscriptions Update" +msgstr "Mise à jour de WooCommerce Subscriptions" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:36 +msgid "" +"Rest assured, although the update process may take a little while, it is " +"coded to prevent defects, your site is safe and will be up and running again," +" faster than ever, shortly." +msgstr "" +"Rassurez-vous, bien que le processus de mise à jour puisse prendre un peu de " +"temps, il est codé pour éviter les défauts, votre site est sûr et sera à " +"nouveau opérationnel, plus rapidement que jamais, sous peu." + +#. translators: placeholder is number of seconds +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:34 +msgid "" +"If you received a server error and reloaded the page to find this notice, " +"please refresh the page in %s seconds and the upgrade routine will " +"recommence without issues." +msgstr "" +"Si vous avez reçu une erreur de serveur et que vous voyez cet avis après " +"avoir rechargé la page, veuillez rafraîchir la page dans %s secondes et la " +"routine de mise à niveau recommencera sans problème." + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:31 +msgid "" +"The WooCommerce Subscriptions plugin is currently running its database " +"upgrade routine." +msgstr "" +"L’extension WooCommerce Subscriptions exécute actuellement sa routine de " +"mise à niveau de la base de données." + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:30 +msgid "The Upgrade is in Progress" +msgstr "La mise à niveau est en cours" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:24 +msgid "WooCommerce Subscriptions Update in Progress" +msgstr "Mise à jour de WooCommerce Subscriptions en cours" + +#: includes/upgrades/templates/wcs-about-2-0.php:194 +msgid "Go to WooCommerce Subscriptions Settings" +msgstr "Accéder aux paramètres de WooCommerce Subscriptions" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about-2-0.php:188 +msgid "" +"Want to list all the subscriptions on a site? Get %sexample.com/wc-" +"api/v2/subscriptions/%s. Want the details of a specific subscription? Get " +"%s/wc-api/v2/subscriptions//%s." +msgstr "" +"Vous voulez répertorier tous les abonnements sur un site ? Obtenez %sexample." +"com/wc-api/v2/subscriptions/%s. Vous voulez les détails d’un abonnement " +"spécifique ? Obtenez %s/wc-api/v2/subscriptions//%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:185 +msgid "" +"We didn't just improve interfaces for humans, we also improved them for " +"computers. Your applications can now create, read, update or delete " +"subscriptions via RESTful API endpoints." +msgstr "" +"Nous n’avons pas seulement amélioré les interfaces pour les humains, nous " +"les avons également améliorées pour les ordinateurs. Vos applications " +"peuvent désormais créer, lire, mettre à jour ou supprimer des abonnements " +"via des points de terminaison API RESTful." + +#: includes/upgrades/templates/wcs-about-2-0.php:184 +msgid "REST API Endpoints" +msgstr "Points de terminaison API REST" + +#. translators: all placeholders are opening and closing tags, no need +#. to order them +#: includes/upgrades/templates/wcs-about-2-0.php:180 +msgid "" +"Because the %sWC_Subscription%s class extends %sWC_Order%s, you can use its " +"familiar methods, like %s$subscription->update_status()%s or %s$subscription-" +">get_total()%s." +msgstr "" +"Comme la classe %sWC_Subscription%s inclut %sWC_Order%s, vous pouvez " +"utiliser ses méthodes familières, comme %s$subscription->update_status()%s " +"ou %s$subscription->get_total()%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:177 +msgid "" +"Subscriptions 2.0 introduces a new object for working with a subscription at " +"the application level. The cumbersome APIs for retrieving or modifying a " +"subscription's data are gone!" +msgstr "" +"Subscriptions 2.0 introduit un nouvel objet pour fonctionner avec un " +"abonnement au niveau de l’application. Les API encombrantes pour récupérer " +"ou modifier les données d’un abonnement ont disparu !" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:175 +msgid "New %sWC_Subscription%s Object" +msgstr "Nouvel objet %sWC_Subscription%s" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:169 +msgid "" +"Developers can also now use all the familiar WordPress functions, like " +"%sget_posts()%s, to query or modify subscription data." +msgstr "" +"De même, les développeurs peuvent désormais utiliser toutes les fonctions " +"WordPress familières, comme %sget_posts()%s, pour interroger ou modifier les " +"données d’abonnement." + +#: includes/upgrades/templates/wcs-about-2-0.php:166 +msgid "" +"By making a subscription a Custom Order Type, a subscription is also now a " +"custom post type. This makes it faster to query subscriptions and it uses a " +"database schema that is as scalable as WordPress posts and pages." +msgstr "" +"En faisant d’un abonnement un type de commande personnalisé, un abonnement " +"devient également un type d’article personnalisé. Cela accélère " +"l’interrogation des abonnements et utilise un schéma de base de données " +"aussi évolutif que les articles et les pages WordPress." + +#. translators: placeholders are opening and closing code tags +#: includes/upgrades/templates/wcs-about-2-0.php:164 +msgid "New %sshop_subscription%s Post Type" +msgstr "Nouveau type d’article %sshop_subscription%s" + +#: includes/upgrades/templates/wcs-about-2-0.php:158 +msgid "" +"Subscriptions 2.0 introduces a new architecture built on the WooCommerce " +"Custom Order Types API." +msgstr "" +"Subscriptions 2.0 introduit une nouvelle architecture basée sur l’API " +"WooCommerce Custom Order Types." + +#: includes/upgrades/templates/wcs-about-2-0.php:157 +#: includes/upgrades/templates/wcs-about.php:151 +msgid "Peek Under the Hood for Developers" +msgstr "Informations détaillées pour les développeurs" + +#: includes/upgrades/templates/wcs-about-2-0.php:150 +msgid "And much more..." +msgstr "Et bien plus encore…" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:137 +msgid "" +"It was already possible to change a subscription's next payment date, but " +"some store managers wanted to provide a customer with an extended free trial " +"or add an extra month to the expiration date. Now you can change all of " +"these dates from the %sEdit Subscription%s screen." +msgstr "" +"Il était déjà possible de modifier la date du prochain paiement d’un " +"abonnement, mais certains gérants de boutique souhaitaient proposer à un " +"client un essai gratuit prolongé ou ajouter un mois supplémentaire à la date " +"d’expiration. Nous pouvez désormais modifier toutes ces dates sur l’écran " +"%sModifier l’abonnement%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:134 +msgid "Change Trial and End Dates" +msgstr "Modifier les dates d’essai et de fin" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:124 +msgid "" +"For a store manager to change a subscription from automatic to manual " +"renewal payments (or manual to automatic) with Subscriptions v1.5, the " +"database needed to be modified directly. Subscriptions now provides a way " +"for payment gateways to allow you to change that from the new %sEdit " +"Subscription%s interface." +msgstr "" +"Pour qu’un gérant de boutique puisse changer un abonnement de paiements de " +"renouvellement automatiques à manuels (ou de manuels à automatiques) avec " +"Subscriptions v1.5, la base de données devait être modifiée directement. " +"Subscriptions permet désormais aux passerelles de paiement de vous autoriser " +"à changer cela dans la nouvelle interface %sModifier l’abonnement%s." + +#. translators: placeholders are for opening and closing link () tags +#. translators: placeholders are opening and closing anchor tags linking to +#. documentation +#: includes/upgrades/templates/wcs-about-2-0.php:115 +#: includes/upgrades/templates/wcs-about-2-0.php:128 +#: includes/upgrades/templates/wcs-about-2-0.php:141 +#: includes/upgrades/templates/wcs-about.php:120 +#: includes/upgrades/templates/wcs-about.php:131 +#: includes/upgrades/templates/wcs-about.php:142 +#: includes/upgrades/templates/wcs-about.php:170 +#: includes/upgrades/templates/wcs-about.php:191 +msgid "%sLearn more »%s" +msgstr "%sEn savoir plus »%s" + +#. translators: placeholders are for opening and closing link () tags +#: includes/upgrades/templates/wcs-about-2-0.php:111 +msgid "" +"By default, adding new files to an existing subscription product will " +"automatically provide active subscribers with access to the new files. " +"However, now you can enable a %snew content dripping setting%s to provide " +"subscribers with access to new files only after the next renewal payment." +msgstr "" +"Par défaut, l’ajout de nouveaux fichiers à un produit d’abonnement existant " +"fournira automatiquement aux abonnés actifs l’accès aux nouveaux fichiers. " +"Cependant, vous pouvez activer un %snouveau paramètre de diffusion de " +"contenu%s pour permettre aux abonnés d’accéder aux nouveaux fichiers " +"uniquement après le prochain paiement de renouvellement." + +#: includes/admin/class-wc-subscriptions-admin.php:1348 +#: includes/upgrades/templates/wcs-about-2-0.php:108 +msgid "Drip Downloadable Content" +msgstr "Diffuser le contenu téléchargeable" + +#. translators: placeholders are opening and closing link tags +#: includes/upgrades/templates/wcs-about-2-0.php:97 +msgid "Learn more about the new %sView Subscription page%s." +msgstr "En savoir plus sur la nouvelle %spage Afficher l’abonnement%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:93 +msgid "" +"This new page is also where the customer can suspend or cancel their " +"subscription, change payment method, change shipping address or " +"upgrade/downgrade an item." +msgstr "" +"Cette nouvelle page permet également au client de suspendre ou d’annuler son " +"abonnement, de modifier le moyen de paiement, de modifier l’adresse de " +"livraison ou de mettre à niveau/rétrograder un article." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:91 +msgid "" +"Your customers can now view the full details of a subscription, including " +"line items, billing and shipping address, billing schedule and renewal " +"orders, from a special %sMy Account > View Subscription%s page." +msgstr "" +"Vos clients peuvent désormais voir tous les détails d’un abonnement, " +"notamment les articles d'une ligne, l’adresse de facturation et de livraison," +" le calendrier de facturation et les commandes de renouvellement, sur une " +"page spéciale %sMon compte > Afficher l’abonnement%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:87 +msgid "New View Subscription Page" +msgstr "Nouvelle page Afficher l’abonnement" + +#. translators: placeholers are link tags: 1$-2$ new subscription page, 3$-4$: +#. docs on woocommerce.com +#: includes/upgrades/templates/wcs-about-2-0.php:76 +msgid "" +"%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new interface." +msgstr "" +"%1$sAjoutez un abonnement%2$s maintenant ou %3$sdécouvrez%4$s la nouvelle " +"interface." + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:72 +msgid "" +"The new interface is also built on the existing %sEdit Order%s screen. If " +"you've ever modified an order, you already know how to modify a subscription." +msgstr "" +"La nouvelle interface est également basée sur l’écran %sModifier la " +"commande%s existant. Si vous avez déjà modifié une commande, vous savez déjà " +"comment modifier un abonnement." + +#: includes/upgrades/templates/wcs-about-2-0.php:69 +msgid "" +"Subscriptions v2.0 introduces a new administration interface to add or edit " +"a subscription. You can make all the familiar changes, like modifying " +"recurring totals or subscription status. You can also make some new " +"modifications, like changing the expiration date, adding a shipping cost or " +"adding a product line item." +msgstr "" +"Subscriptions v2.0 introduit une nouvelle interface d’administration pour " +"ajouter ou modifier un abonnement. Vous pouvez apporter toutes les " +"modifications habituelles, comme la modification des totaux récurrents ou de " +"l’état de l’abonnement. Vous pouvez également apporter de nouvelles " +"modifications, comme modifier la date d’expiration, ajouter des frais de " +"port ou ajouter article d'une ligne de produits." + +#: includes/upgrades/templates/wcs-about-2-0.php:68 +msgid "New Add/Edit Subscription Screen" +msgstr "Nouvel écran Ajouter/Modifier un abonnement" + +#. translators: placeholders are opening and closing link tags +#: includes/upgrades/templates/wcs-about-2-0.php:56 +msgid "Learn more about the new %smultiple subscriptions%s feature." +msgstr "" +"En savoir plus sur la nouvelle fonctionnalité %sabonnements multiples%s." + +#: includes/upgrades/templates/wcs-about-2-0.php:53 +msgid "" +"Customers can now purchase different subscription products in one " +"transaction. The products can bill on any schedule and have any combination " +"of sign-up fees and/or free trials." +msgstr "" +"Les clients peuvent désormais acheter différents produits d’abonnement en " +"une seule transaction. Les produits peuvent être facturés selon n’importe " +"quel calendrier et avoir n’importe quelle combinaison de frais d’inscription " +"et/ou d’essais gratuits." + +#: includes/upgrades/templates/wcs-about-2-0.php:52 +msgid "It's now easier for your customers to buy more subscriptions!" +msgstr "" +"Il est désormais plus facile pour vos clients d’acheter plus d’abonnements !" + +#: includes/upgrades/templates/wcs-about-2-0.php:51 +msgid "Multiple Subscriptions" +msgstr "Abonnements multiples" + +#: includes/upgrades/templates/wcs-about-2-0.php:42 +#: includes/upgrades/templates/wcs-about.php:41 +msgid "Check Out What's New" +msgstr "Découvrir les nouveautés" + +#. translators: placeholder is version number +#: includes/upgrades/templates/wcs-about-2-0.php:31 +#: includes/upgrades/templates/wcs-about.php:30 +msgid "Version %s" +msgstr "Version %s" + +#: includes/upgrades/templates/update-welcome-notice.php:6 +#: includes/upgrades/templates/wcs-about-2-0.php:25 +#: includes/upgrades/templates/wcs-about.php:24 +msgid "We hope you enjoy it!" +msgstr "Nous espérons que vous l’apprécierez !" + +#: includes/upgrades/templates/wcs-about-2-0.php:24 +msgid "" +"Version 2.0 has been in development for more than a year. We've reinvented " +"the extension to take into account 3 years of feedback from store managers." +msgstr "" +"La version 2.0 est en développement depuis plus d’un an. Nous avons " +"réinventé l’extension pour prendre en compte 3 ans de commentaires de la " +"part des gérants de boutique." + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/templates/update-welcome-notice.php:2 +#: includes/upgrades/templates/wcs-about-2-0.php:23 +#: includes/upgrades/templates/wcs-about.php:22 +msgid "" +"Thank you for updating to the latest version of WooCommerce Subscriptions." +msgstr "Merci d’être passé à la dernière version de WooCommerce Subscriptions." + +#: includes/upgrades/templates/wcs-about-2-0.php:20 +msgid "Welcome to Subscriptions 2.0" +msgstr "Bienvenue dans Subscriptions 2.0" + +#: includes/upgrades/class-wc-subscriptions-upgrader.php:640 +msgid "About WooCommerce Subscriptions" +msgstr "À propos de WooCommerce Subscriptions" + +#: includes/upgrades/class-wc-subscriptions-upgrader.php:640 +msgid "Welcome to WooCommerce Subscriptions 2.1" +msgstr "Bienvenue dans WooCommerce Subscriptions 2.1" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, +#. 4$: break tag +#: includes/upgrades/class-wc-subscriptions-upgrader.php:389 +msgid "" +"Unable to upgrade subscriptions.%4$sError: %1$s%4$sPlease refresh the page " +"and try again. If problem persists, %2$scontact support%3$s." +msgstr "" +"Impossible de mettre à niveau les abonnements.%4$sErreur : %1$s%4$sVeuillez " +"rafraîchir la page et réessayer. Si le problème persiste, %2$scontactez " +"l’assistance%3$s." + +#. translators: placeholder is number of upgraded subscriptions +#: includes/upgrades/class-wc-subscriptions-upgrader.php:355 +msgctxt "used in the subscriptions upgrader" +msgid "Marked %s subscription products as \"sold individually\"." +msgstr "%s produits d’abonnement marqués comme « vendus individuellement »." + +#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 & +#. 1.5") +#: includes/upgrades/class-wc-subscriptions-upgrader.php:347 +msgid "Database updated to version %s" +msgstr "Base de données mise à jour vers la version %s" + +#: includes/payment-retry/class-wcs-retry-post-store.php:47 +msgid "No retries found in trash" +msgstr "Aucune nouvelle tentative trouvée dans la corbeille" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:138 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:229 +#: includes/payment-retry/class-wcs-retry-post-store.php:40 +msgid "Edit" +msgstr "Modifier" + +#: includes/payment-retry/class-wcs-retry-post-store.php:38 +msgid "Add" +msgstr "Ajouter" + +#. translators: placeholder is a number of days. +#: includes/wcs-time-functions.php:58 +msgid "%s day" +msgid_plural "a %s-day" +msgstr[0] "%s jour" +msgstr[1] "de %s jours" + +#. translators: placeholder is a number of weeks. +#: includes/wcs-time-functions.php:60 +msgid "%s week" +msgid_plural "a %s-week" +msgstr[0] "%s semaine" +msgstr[1] "de %s semaines" + +#. translators: placeholder is a number of months. +#: includes/wcs-time-functions.php:62 +msgid "%s month" +msgid_plural "a %s-month" +msgstr[0] "%s mois" +msgstr[1] "de %s mois" + +#. translators: placeholder is a number of years. +#: includes/wcs-time-functions.php:64 +msgid "%s year" +msgid_plural "a %s-year" +msgstr[0] "%s an" +msgstr[1] "de %s ans" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:66 +msgid "Subscription reactivated with PayPal" +msgstr "Abonnement réactivé avec PayPal" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:53 +msgid "Subscription suspended with PayPal" +msgstr "Abonnement suspendu avec PayPal" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42 +msgid "Subscription cancelled with PayPal" +msgstr "Abonnement annulé avec PayPal" + +#. translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma +#. separated +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:78 +msgctxt "item name sent to paypal" +msgid "Subscription %1$s (Order %2$s) - %3$s" +msgstr "Abonnement %1$s (Commande %2$s) - %3$s" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:503 +msgid "IPN subscription payment failure." +msgstr "Échec du paiement d’abonnement IPN." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:487 +msgid "IPN subscription cancelled." +msgstr "Abonnement IPN annulé." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:464 +msgid "IPN subscription suspended." +msgstr "Abonnement IPN suspendu." + +#. translators: placeholder is payment status (e.g. "completed") +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:422 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:431 +msgctxt "used in order note" +msgid "IPN subscription payment %s." +msgstr "Paiement d’abonnement IPN %s." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:374 +msgid "IPN subscription failing payment method changed." +msgstr "Abonnement IPN échouant au moyen de paiement modifié." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:332 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:412 +msgid "IPN subscription payment completed." +msgstr "Paiement d’abonnement IPN terminé." + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:279 +msgid "IPN subscription sign up completed." +msgstr "Inscription d’abonnement IPN terminée." + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php:94 +msgid "Billing agreement cancelled at PayPal." +msgstr "Accord de facturation annulé chez PayPal." + +#: includes/privacy/class-wcs-privacy.php:236 +msgid "N/A" +msgstr "ND" + +#. translators: placeholder is localised datetime +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119 +msgid "expected clearing date %s" +msgstr "date de compensation prévue %s" + +#. translators: %s: product SKU. +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:536 +msgid "SKU: %s" +msgstr "UGS : %s" + +#. translators: 1$: new status (e.g. "Cancel"), 2$: blog name +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:416 +msgctxt "data sent to paypal" +msgid "%1$s subscription event triggered at %2$s" +msgstr "%1$s événement d’abonnement déclenché sur %2$s" + +#. translators: placeholder is blogname +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:306 +msgid "%s - Order" +msgstr "%s - Commande" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:279 +msgid "Total Discount" +msgstr "Remise totale" + +#. translators: placeholder is blogname +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:71 +msgctxt "data sent to paypal" +msgid "Orders with %s" +msgstr "Commandes avec %s" + +#. translators: placeholders are opening and closing link tags. 1$-2$: docs on +#. woocommerce, 3$-4$: dismiss link +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:172 +msgid "" +"There is a problem with PayPal. Your PayPal account is issuing out-of-date " +"subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." +msgstr "" +"Il y a un problème avec PayPal. Votre compte PayPal émet des ID d’abonnement " +"obsolètes. %1$sEn savoir plus%2$s. %3$sIgnorer%4$s." + +#. translators: placeholders are link opening and closing tags. 1$-2$: to +#. gateway settings, 3$-4$: support docs on woocommerce.com +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:159 +msgid "" +"There is a problem with PayPal. Your API credentials may be incorrect. " +"Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s." +msgstr "" +"Il y a un problème avec PayPal. Vos identifiants de connexion API peuvent " +"être incorrects. Veuillez mettre à jour vos %1$sidentifiants de connexion " +"API%2$s. %3$sEn savoir plus%4$s." + +#. translators: placeholders are opening and closing strong tags. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:148 +msgid "" +"%1$sPayPal Reference Transactions are enabled on your account%2$s. All " +"subscription management features are now enabled. Happy selling!" +msgstr "" +"%1$sPayPal Reference Transactions est activé sur votre compte%2$s. Toutes " +"les fonctionnalités de gestion des abonnements sont maintenant activées. " +"Bonne vente !" + +#. translators: opening/closing tags - links to documentation. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122 +msgid "" +"%1$sPayPal Reference Transactions are not enabled on your account%2$s, some " +"subscription management features are not enabled. Please contact PayPal and " +"request they %3$senable PayPal Reference Transactions%4$s on your account. " +"%5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" +"%1$sPayPal Reference Transactions n’est pas activé sur votre compte%2$s, " +"certaines fonctionnalités de gestion des abonnements ne sont pas activées. " +"Veuillez contacter PayPal et leur demander d’%3$sactiver PayPal Reference " +"Transactions%4$s sur votre compte. %5$sVérifier le compte PayPal%6$s %3$sEn " +"savoir plus%7$s" + +#. translators: placeholders are opening and closing link tags. 1$-2$: to docs +#. on woocommerce, 3$-4$ to gateway settings on the site +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:110 +msgid "" +"PayPal is inactive for subscription transactions. Please %1$sset up the " +"PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for " +"Subscriptions." +msgstr "" +"PayPal est inactif pour les transactions d’abonnement. Veuillez " +"%1$sconfigurer l’IPN PayPal%2$s et %3$ssaisir vos identifiants de connexion " +"API%4$s afin d’activer PayPal pour Subscriptions." + +#. translators: $1 and $2 are opening and closing strong tags, respectively. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:63 +msgid "" +"It is %1$sstrongly recommended you do not change the Receiver Email " +"address%2$s if you have active subscriptions with PayPal. Doing so can break " +"existing subscriptions." +msgstr "" +"Il vous est %1$sfortement recommandé de ne pas modifier l’adresse e-mail du " +"destinataire%2$s si vous avez des abonnements actifs avec PayPal. Cela peut " +"interrompre les abonnements existants." + +#: includes/gateways/paypal/class-wcs-paypal.php:460 +msgid "" +"Are you sure you want to change the payment method from PayPal standard?\n" +"\n" +"This will suspend the subscription at PayPal." +msgstr "" +"Voulez-vous vraiment modifier le moyen de paiement de PayPal Standard ?\n" +"\n" +"Cela suspendra l’abonnement chez PayPal." + +#. translators: placeholder is a transaction ID. +#: includes/gateways/paypal/class-wcs-paypal.php:407 +msgid "PayPal payment approved (ID: %s)" +msgstr "Paiement PayPal approuvé (ID : %s)" + +#. translators: placeholder is PayPal transaction status message +#: includes/gateways/paypal/class-wcs-paypal.php:403 +msgid "PayPal payment declined: %s" +msgstr "Paiement PayPal refusé : %s" + +#. translators: placeholder is PayPal transaction status message +#: includes/gateways/paypal/class-wcs-paypal.php:391 +msgid "PayPal Transaction Held: %s" +msgstr "Transaction PayPal en cours : %s" + +#. translators: placeholders are PayPal API error code and PayPal API error +#. message +#: includes/gateways/paypal/class-wcs-paypal.php:386 +msgid "PayPal API error: (%1$d) %2$s" +msgstr "Erreur d’API PayPal : (%1$d) %2$s" + +#: includes/gateways/paypal/class-wcs-paypal.php:282 +msgid "" +"An error occurred, please try again or try an alternate form of payment." +msgstr "" +"Une erreur est survenue, veuillez réessayer ou essayer un autre mode de " +"paiement." + +#: includes/gateways/paypal/class-wcs-paypal.php:220 +msgid "Unable to find order for PayPal billing agreement." +msgstr "Commande pour l’accord de facturation PayPal introuvable." + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:137 +msgid "" +"Sorry, it seems there are no available payment methods which support " +"subscriptions. Please contact us if you require assistance or wish to make " +"alternate arrangements." +msgstr "" +"Désolé, il semble qu’aucun moyen de paiement ne soit disponible pour les " +"abonnements. Veuillez nous contacter si vous avez besoin d’aide ou si vous " +"désirez mettre en place une alternative." + +#: includes/emails/class-wcs-email-new-switch-order.php:26 +msgid "[{blogname}] Subscription Switched ({order_number}) - {order_date}" +msgstr "[{blogname}] Abonnement changé ({order_number}) - {order_date}" + +#: includes/emails/class-wcs-email-new-switch-order.php:23 +msgid "" +"Subscription switched emails are sent when a customer switches a " +"subscription." +msgstr "" +"Les e-mails de changement d’abonnement sont envoyés lorsqu’un client change " +"d’abonnement." + +#: includes/emails/class-wcs-email-new-switch-order.php:22 +#: includes/emails/class-wcs-email-new-switch-order.php:25 +msgid "Subscription Switched" +msgstr "Abonnement changé" + +#: includes/emails/class-wcs-email-new-renewal-order.php:26 +msgid "" +"[{blogname}] New subscription renewal order ({order_number}) - {order_date}" +msgstr "" +"[{blogname}] Nouvelle commande de renouvellement d’abonnement ({order_number}" +") - {order_date}" + +#: includes/emails/class-wcs-email-new-renewal-order.php:25 +msgid "New subscription renewal order" +msgstr "Nouvelle commande de renouvellement d’abonnement" + +#: includes/emails/class-wcs-email-new-renewal-order.php:23 +msgid "" +"New renewal order emails are sent when a subscription renewal payment is " +"processed." +msgstr "" +"Les e-mails de nouvelle commande de renouvellement sont envoyés lorsqu’un " +"paiement de renouvellement d’abonnement est traité." + +#: includes/emails/class-wcs-email-new-renewal-order.php:22 +msgid "New Renewal Order" +msgstr "Nouvelle commande de renouvellement" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:49 +msgid "Invoice for renewal order {order_number}" +msgstr "Facture pour la commande de renouvellement {order_number}" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:48 +msgid "Invoice for renewal order {order_number} from {order_date}" +msgstr "" +"Facture pour la commande de renouvellement {order_number} du {order_date}" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:40 +msgid "Customer Renewal Invoice" +msgstr "Facture de renouvellement client" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:29 +msgid "Your {blogname} renewal order receipt from {order_date}" +msgstr "Votre reçu de commande de renouvellement de {blogname} du {order_date}" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:28 +msgid "Thank you for your order" +msgstr "Merci pour votre commande" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:25 +msgid "" +"This is an order notification sent to the customer after payment for a " +"subscription renewal order is completed. It contains the renewal order " +"details." +msgstr "" +"Il s’agit d’une notification de commande envoyée au client après le paiement " +"d’une commande de renouvellement d’abonnement. Elle contient les détails de " +"la commande de renouvellement." + +#: includes/emails/class-wcs-email-processing-renewal-order.php:24 +msgid "Processing Renewal order" +msgstr "Traitement de la commande de renouvellement" + +#: includes/emails/class-wcs-email-completed-switch-order.php:39 +msgid "" +"Your {blogname} subscription change from {order_date} is complete - download " +"your files" +msgstr "" +"Votre changement d’abonnement de {blogname} du {order_date} est terminé, " +"téléchargez vos fichiers" + +#: includes/emails/class-wcs-email-completed-switch-order.php:38 +msgid "Your subscription change is complete - download your files" +msgstr "Votre changement d’abonnement est terminé, téléchargez vos fichiers" + +#: includes/emails/class-wcs-email-completed-switch-order.php:31 +msgid "Your {blogname} subscription change from {order_date} is complete" +msgstr "" +"Votre changement d’abonnement de {blogname} du {order_date} est terminé" + +#: includes/emails/class-wcs-email-completed-switch-order.php:30 +msgid "Your subscription change is complete" +msgstr "Votre changement d’abonnement est terminé" + +#: includes/emails/class-wcs-email-completed-switch-order.php:27 +msgid "" +"Subscription switch complete emails are sent to the customer when a " +"subscription is switched successfully." +msgstr "" +"Les e-mails de changement d’abonnement terminé sont envoyés au client " +"lorsqu’un abonnement est changé avec succès." + +#: includes/emails/class-wcs-email-completed-switch-order.php:26 +msgid "Subscription Switch Complete" +msgstr "Changement d’abonnement terminé" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:26 +msgid "" +"Renewal order complete emails are sent to the customer when a subscription " +"renewal order is marked complete and usually indicates that the item for " +"that renewal period has been shipped." +msgstr "" +"Des e-mails de fin de commande de renouvellement sont envoyés au client " +"lorsqu’une commande de renouvellement d’abonnement est marquée comme " +"terminée. Ils indiquent en général que l’article pour cette période de " +"renouvellement a été expédié." + +#: includes/emails/class-wcs-email-completed-renewal-order.php:25 +msgid "Completed Renewal Order" +msgstr "Commande de renouvellement terminée" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:181 +#: includes/emails/class-wcs-email-expired-subscription.php:179 +#: includes/emails/class-wcs-email-on-hold-subscription.php:179 +msgctxt "email type" +msgid "Multipart" +msgstr "Multi-parties" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:180 +#: includes/emails/class-wcs-email-expired-subscription.php:178 +#: includes/emails/class-wcs-email-on-hold-subscription.php:178 +msgctxt "email type" +msgid "HTML" +msgstr "HTML" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:179 +#: includes/emails/class-wcs-email-expired-subscription.php:177 +#: includes/emails/class-wcs-email-on-hold-subscription.php:177 +msgctxt "email type" +msgid "Plain text" +msgstr "Texte brut" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:175 +#: includes/emails/class-wcs-email-expired-subscription.php:173 +#: includes/emails/class-wcs-email-on-hold-subscription.php:173 +msgid "Choose which format of email to send." +msgstr "Choisissez le format d’envoi des e-mails." + +#. translators: %s: default e-mail heading. +#: includes/emails/class-wcs-email-expired-subscription.php:166 +#: includes/emails/class-wcs-email-on-hold-subscription.php:166 +msgid "" +"This controls the main heading contained within the email notification. " +"Leave blank to use the default heading: %s." +msgstr "" +"Cela contrôle l’en-tête principal contenu dans la notification par e-mail. " +"Laisser vide pour utiliser l’en-tête par défaut : %s." + +#. translators: %s: default e-mail subject. +#: includes/emails/class-wcs-email-cancelled-subscription.php:160 +#: includes/emails/class-wcs-email-expired-subscription.php:158 +#: includes/emails/class-wcs-email-on-hold-subscription.php:158 +msgid "" +"This controls the email subject line. Leave blank to use the default subject:" +" %s." +msgstr "" +"Cela contrôle la ligne d’objet de l’e-mail. Laisser vide pour utiliser le " +"sujet par défaut : %s." + +#: includes/emails/class-wcs-email-cancelled-subscription.php:157 +#: includes/emails/class-wcs-email-expired-subscription.php:155 +#: includes/emails/class-wcs-email-on-hold-subscription.php:155 +msgctxt "of an email" +msgid "Subject" +msgstr "Sujet" + +#. translators: placeholder is admin email +#: includes/emails/class-wcs-email-cancelled-subscription.php:152 +#: includes/emails/class-wcs-email-expired-subscription.php:150 +#: includes/emails/class-wcs-email-on-hold-subscription.php:150 +msgid "Enter recipients (comma separated) for this email. Defaults to %s." +msgstr "" +"Saisir les destinataires (séparés par une virgule) pour cet e-mail. Par " +"défaut à %s." + +#: includes/emails/class-wcs-email-cancelled-subscription.php:149 +#: includes/emails/class-wcs-email-expired-subscription.php:147 +#: includes/emails/class-wcs-email-on-hold-subscription.php:147 +msgctxt "of an email" +msgid "Recipient(s)" +msgstr "Destinataire(s)" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:145 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:212 +#: includes/emails/class-wcs-email-expired-subscription.php:143 +#: includes/emails/class-wcs-email-on-hold-subscription.php:143 +msgid "Enable this email notification" +msgstr "Activer cette notification par e-mail" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:143 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:210 +#: includes/emails/class-wcs-email-expired-subscription.php:141 +#: includes/emails/class-wcs-email-on-hold-subscription.php:141 +msgctxt "an email notification" +msgid "Enable/Disable" +msgstr "Activer/Désactiver" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:29 +msgid "Subscription Cancelled" +msgstr "Abonnement annulé" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:27 +msgid "" +"Cancelled Subscription emails are sent when a customer's subscription is " +"cancelled (either by a store manager, or the customer)." +msgstr "" +"Les e-mails d’abonnement annulé sont envoyés lorsque l’abonnement d’un " +"client est annulé (par un gérant de boutique ou par le client)." + +#: includes/emails/class-wcs-email-cancelled-subscription.php:26 +msgid "Cancelled Subscription" +msgstr "Abonnement annulé" + +#: includes/class-wcs-webhooks.php:112 +msgid " Subscription deleted" +msgstr "Abonnement supprimé" + +#: includes/class-wcs-webhooks.php:111 +msgid " Subscription updated" +msgstr "Abonnement mis à jour" + +#: includes/class-wcs-webhooks.php:110 +msgid " Subscription created" +msgstr "Abonnement créé" + +#. translators: placeholder is subscription's new status, translated +#: includes/class-wcs-user-change-status-handler.php:116 +msgid "" +"That subscription can not be changed to %s. Please contact us if you need " +"assistance." +msgstr "" +"Cet abonnement ne peut pas être modifié sur %s. Contactez-nous si vous avez " +"besoin d’aide." + +#: includes/class-wcs-user-change-status-handler.php:103 +msgid "" +"That subscription does not exist. Please contact us if you need assistance." +msgstr "" +"Cet abonnement n’existe pas. Contactez-nous si vous avez besoin d’aide." + +#: includes/class-wcs-user-change-status-handler.php:71 +msgid "" +"You can not suspend that subscription - the suspension limit has been " +"reached. Please contact us if you need assistance." +msgstr "" +"Vous ne pouvez pas suspendre cet abonnement - la limite de suspension a été " +"atteinte. Contactez-nous si vous avez besoin d’aide." + +#: includes/class-wcs-user-change-status-handler.php:61 +msgid "" +"You can not reactivate that subscription until paying to renew it. Please " +"contact us if you need assistance." +msgstr "" +"Vous ne pouvez pas réactiver cet abonnement tant que vous n’avez pas payé " +"pour le renouveler. Contactez-nous si vous avez besoin d’aide." + +#: includes/class-wcs-remove-item.php:188 +msgid "" +"The item was not removed because this Subscription's payment method does not " +"support removing an item." +msgstr "" +"L’article n’a pas été supprimé, car le moyen de paiement de cet abonnement " +"ne prend pas en charge la suppression d’un article." + +#: includes/class-wcs-remove-item.php:184 +msgid "You cannot remove an item that does not exist. " +msgstr "Vous ne pouvez pas supprimer un article qui n’existe pas. " + +#: includes/class-wcs-remove-item.php:180 +msgid "You cannot modify a subscription that does not belong to you." +msgstr "Vous ne pouvez pas modifier un abonnement qui ne vous appartient pas." + +#: includes/class-wcs-remove-item.php:176 +#: includes/class-wcs-user-change-status-handler.php:107 +msgid "Security error. Please contact us if you need assistance." +msgstr "Erreur de sécurité. Contactez-nous si vous avez besoin d’aide." + +#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: +#. closing link tags +#: includes/class-wcs-remove-item.php:140 +msgid "" +"You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" +msgstr "" +"Vous avez bien supprimé « %1$s » de votre abonnement. %2$sAnnuler ?%3$s" + +#. translators: 1$: product name, 2$: product id +#: includes/class-wcs-remove-item.php:137 +msgctxt "used in order note" +msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" +"Le client a supprimé « %1$s » (ID produit : n°%2$d) sur la page Mon compte." + +#: includes/class-wcs-remove-item.php:119 +msgid "Your request to undo your previous action was unsuccessful." +msgstr "Votre demande d’annulation de votre action précédente a échoué." + +#. translators: 1$: product name, 2$: product id +#: includes/class-wcs-remove-item.php:114 +msgctxt "used in order note" +msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" +"Le client a ajouté « %1$s » (ID produit : n°%2$d) sur la page Mon compte." + +#. translators: %d: subscription ID. +#: includes/class-wcs-remove-item.php:79 +msgctxt "hash before subscription ID" +msgid "Subscription #%d does not exist." +msgstr "L’abonnement n°%d n’existe pas." + +#. translators: %s: subscription ID. +#. translators: %s: order number. +#. translators: placeholder is a subscription ID. +#: includes/class-wc-subscriptions-addresses.php:207 +#: includes/class-wc-subscriptions-change-payment-gateway.php:741 +#: includes/class-wcs-query.php:101 +msgctxt "hash before order number" +msgid "Subscription #%s" +msgstr "Abonnement n°%s" + +#: includes/class-wcs-change-payment-method-admin.php:122 +msgid "Please choose a valid payment gateway to change to." +msgstr "" +"Veuillez choisir une passerelle de paiement valide vers laquelle passer." + +#: includes/class-wcs-cart-resubscribe.php:91 +#: includes/class-wcs-cart-resubscribe.php:119 +msgid "Complete checkout to resubscribe." +msgstr "Terminez la validation de commande pour vous réabonner." + +#: includes/class-wcs-cart-resubscribe.php:82 +msgid "" +"You can not resubscribe to that subscription. Please contact us if you need " +"assistance." +msgstr "" +"Vous ne pouvez pas vous réabonner à cet abonnement. Contactez-nous si vous " +"avez besoin d’aide." + +#: includes/class-wcs-cart-resubscribe.php:74 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:91 +msgid "That subscription does not exist. Has it been deleted?" +msgstr "Cet abonnement n’existe pas. A-t-il été supprimé ?" + +#: includes/class-wcs-cart-resubscribe.php:70 +msgid "There was an error with your request to resubscribe. Please try again." +msgstr "" +"Une erreur est survenue lors de votre demande de réabonnement. Veuillez " +"réessayer." + +#: includes/class-wcs-cart-renewal.php:647 +msgid "All linked subscription items have been removed from the cart." +msgstr "Tous les articles d’abonnement liés ont été supprimés du panier." + +#: includes/class-wcs-cart-renewal.php:376 +msgid "" +"We couldn't find the original renewal order for an item in your cart. The " +"item was removed." +msgid_plural "" +"We couldn't find the original renewal orders for items in your cart. The " +"items were removed." +msgstr[0] "" +"Nous n’avons pas trouvé la commande de renouvellement d’origine pour un " +"article dans votre panier. L’article a été supprimé." +msgstr[1] "" +"Nous n’avons pas trouvé les commandes de renouvellement d’origine pour des " +"articles dans votre panier. Les articles ont été supprimés." + +#: includes/class-wcs-cart-renewal.php:369 +msgid "" +"We couldn't find the original subscription for an item in your cart. The " +"item was removed." +msgid_plural "" +"We couldn't find the original subscriptions for items in your cart. The " +"items were removed." +msgstr[0] "" +"Nous n’avons pas trouvé l’abonnement d’origine pour un article dans votre " +"panier. L’article a été supprimé." +msgstr[1] "" +"Nous n’avons pas trouvé les abonnements d’origine pour des articles dans " +"votre panier. Les articles ont été supprimés." + +#. translators: %s is subscription's number +#: includes/class-wcs-cart-renewal.php:327 +msgid "Subscription #%s has not been added to the cart." +msgstr "L’abonnement n°%s n’a pas été ajouté au panier." + +#. translators: placeholder is an item name +#: includes/class-wcs-cart-renewal.php:292 +msgid "" +"The %s product has been deleted and can no longer be renewed. Please choose " +"a new product or contact us for assistance." +msgstr "" +"Le produit %s a été supprimé et ne peut plus être renouvelé. Veuillez " +"choisir un nouveau produit ou nous contacter pour obtenir de l’aide." + +#: includes/class-wcs-cart-initial-payment.php:62 +#: includes/class-wcs-cart-renewal.php:194 +msgid "That doesn't appear to be your order." +msgstr "Cela ne semble pas être votre commande." + +#: includes/class-wcs-auth.php:45 +msgid "View and manage subscriptions" +msgstr "Afficher et gérer les abonnements" + +#: includes/class-wcs-auth.php:42 +msgid "Create subscriptions" +msgstr "Créer des abonnements" + +#: includes/class-wcs-auth.php:39 +msgid "View subscriptions" +msgstr "Afficher les abonnements" + +#. translators: placeholder is a date +#: includes/class-wc-subscriptions-synchroniser.php:841 +msgid "First payment: %s" +msgstr "Premier paiement : %s" + +#. translators: placeholder is a date +#: includes/class-wc-subscriptions-synchroniser.php:838 +msgid "First payment prorated. Next payment: %s" +msgstr "Premier paiement au prorata. Paiement suivant : %s" + +#: includes/class-wc-subscriptions-synchroniser.php:831 +msgid "Today!" +msgstr "Aujourd’hui !" + +#: includes/class-wc-subscriptions-synchroniser.php:783 +msgid "Last day of the month" +msgstr "Dernier jour du mois" + +#. translators: placeholder is a number of day with language specific suffix +#. applied (e.g. "1st", "3rd", "5th", etc...) +#: includes/class-wc-subscriptions-synchroniser.php:781 +msgid "%s day of the month" +msgstr "%s jour du mois" + +#. translators: placeholder is a day of the week +#: includes/class-wc-subscriptions-synchroniser.php:775 +msgid "%s each week" +msgstr "%s chaque semaine" + +#: includes/class-wc-subscriptions-synchroniser.php:750 +#: includes/class-wc-subscriptions-synchroniser.php:767 +msgid "Do not synchronise" +msgstr "Ne pas synchroniser" + +#: includes/class-wc-subscriptions-switcher.php:432 +#: includes/class-wc-subscriptions-synchroniser.php:235 +msgctxt "when to prorate first payment / subscription length" +msgid "For Virtual Subscription Products Only" +msgstr "Pour les produits d’abonnement virtuels uniquement" + +#: includes/class-wc-subscriptions-synchroniser.php:227 +msgid "" +"If a subscription is synchronised to a specific day of the week, month or " +"year, charge a prorated amount for the subscription at the time of sign up." +msgstr "" +"Si un abonnement est synchronisé sur un jour spécifique de la semaine, du " +"mois ou de l’année, facturez un montant au prorata pour l’abonnement au " +"moment de l’inscription." + +#: includes/class-wc-subscriptions-synchroniser.php:219 +msgid "Align Subscription Renewal Day" +msgstr "Aligner le jour de renouvellement d’abonnement" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-synchroniser.php:213 +msgctxt "used in the general subscription options page" +msgid "" +"Align subscription renewal to a specific day of the week, month or year. For " +"example, the first day of the month. %1$sLearn more%2$s." +msgstr "" +"Alignez le renouvellement d’abonnement sur un jour spécifique de la semaine, " +"du mois ou de l’année. Par exemple, le premier jour du mois. %1$sEn savoir " +"plus%2$s." + +#: includes/class-wc-subscriptions-synchroniser.php:210 +msgid "Synchronisation" +msgstr "Synchronisation" + +#. translators: placeholder is a year (e.g. "2016") +#: includes/class-wc-subscriptions-synchroniser.php:51 +msgctxt "used in subscription product edit screen" +msgid "" +"Align the payment date for this subscription to a specific day of the year. " +"If the date has already taken place this year, the first payment will be " +"processed in %s. Set the day to 0 to disable payment syncing for this " +"product." +msgstr "" +"Alignez la date de paiement de cet abonnement sur un jour spécifique de " +"l’année. Si la date a déjà eu lieu cette année, le premier paiement sera " +"traité en %s. Définissez le jour sur 0 pour désactiver la synchronisation " +"des paiements pour ce produit." + +#: includes/class-wc-subscriptions-synchroniser.php:49 +msgid "" +"Align the payment date for all customers who purchase this subscription to a " +"specific day of the week or month." +msgstr "" +"Alignez la date de paiement pour tous les clients qui achètent cet " +"abonnement sur un jour spécifique de la semaine ou du mois." + +#: templates/admin/deprecated/html-variation-synchronisation.php:30 +msgid "Synchronise Renewals" +msgstr "Synchroniser les renouvellements" + +#. translators: %1: product subtotal, %2: HTML span tag, %3: direction +#. (upgrade, downgrade, crossgrade), %4: closing HTML span tag +#: includes/class-wc-subscriptions-switcher.php:1866 +msgctxt "product subtotal string" +msgid "%1$s %2$s(%3$s)%4$s" +msgstr "%1$s %2$s(%3$s)%4$s" + +#: includes/class-wc-subscriptions-switcher.php:1861 +msgctxt "a switch type" +msgid "Crossgrade" +msgstr "Reclassement" + +#: includes/class-wc-subscriptions-switcher.php:1858 +msgctxt "a switch type" +msgid "Upgrade" +msgstr "Mise à niveau" + +#: includes/class-wc-subscriptions-switcher.php:1855 +msgctxt "a switch type" +msgid "Downgrade" +msgstr "Rétrogradation" + +#: includes/class-wc-subscriptions-switcher.php:1493 +msgid "There was an error locating the switch details." +msgstr "" +"Une erreur est survenue lors de la localisation des détails du changement." + +#: includes/class-wc-subscriptions-switcher.php:1452 +msgid "" +"You can not switch this subscription. It appears you do not own the " +"subscription." +msgstr "" +"Vous ne pouvez pas changer cet abonnement. Il semble que cet abonnement ne " +"vous appartient pas." + +#: includes/class-wc-subscriptions-switcher.php:1405 +msgid "You can not switch to the same subscription." +msgstr "Vous ne pouvez pas passer au même abonnement." + +#: includes/class-wc-subscriptions-switcher.php:1383 +msgid "We can not find your old subscription item." +msgstr "Nous ne trouvons pas votre ancien article d’abonnement." + +#: includes/class-wc-subscriptions-switcher.php:1211 +msgid "Switched Subscription" +msgstr "Abonnement changé" + +#: includes/class-wc-subscriptions-switcher.php:1196 +msgid "Switch Order" +msgstr "Commande de changement" + +#. translators: 1$: old item, 2$: new item when switching +#: includes/class-wc-subscriptions-switcher.php:1985 +msgctxt "used in order notes" +msgid "Customer switched from: %1$s to %2$s." +msgstr "Le client est passé de : %1$s à %2$s." + +#: includes/class-wc-subscriptions-switcher.php:444 +#: includes/class-wc-subscriptions-switcher.php:542 +#: includes/class-wc-subscriptions-switcher.php:2563 +msgid "Upgrade or Downgrade" +msgstr "Mettre à niveau ou rétrograder" + +#: includes/class-wc-subscriptions-switcher.php:440 +msgid "" +"Customise the text displayed on the button next to the subscription on the " +"subscriber's account page. The default is \"Switch Subscription\", but you " +"may wish to change this to \"Upgrade\" or \"Change Subscription\"." +msgstr "" +"Personnalisez le texte affiché sur le bouton en regard de l’abonnement sur " +"la page du compte de l’abonné. Le texte par défaut est « Changer " +"d’abonnement », mais vous pouvez le remplacer par « Mettre à niveau » ou " +"« Modifier l’abonnement »." + +#: includes/class-wc-subscriptions-switcher.php:439 +msgid "Switch Button Text" +msgstr "Texte du bouton de changement" + +#: includes/class-wc-subscriptions-switcher.php:424 +msgid "" +"When switching to a subscription with a length, you can take into account " +"the payments already completed by the customer when determining how many " +"payments the subscriber needs to make for the new subscription." +msgstr "" +"Lors du passage à un abonnement avec une durée, vous pouvez prendre en " +"compte les paiements déjà effectués par le client pour déterminer le nombre " +"de paiements que l’abonné doit effectuer pour le nouvel abonnement." + +#: includes/class-wc-subscriptions-switcher.php:423 +msgid "Prorate Subscription Length" +msgstr "Durée de l’abonnement au prorata" + +#: includes/class-wc-subscriptions-switcher.php:417 +msgctxt "when to prorate signup fee when switching" +msgid "Always" +msgstr "Toujours" + +#: includes/class-wc-subscriptions-switcher.php:416 +msgctxt "when to prorate signup fee when switching" +msgid "Never (charge the full sign up fee)" +msgstr "Jamais (facturer l’intégralité des frais d’inscription)" + +#: includes/class-wc-subscriptions-switcher.php:415 +msgctxt "when to prorate signup fee when switching" +msgid "Never (do not charge a sign up fee)" +msgstr "Jamais (ne pas facturer de frais d’inscription)" + +#: includes/class-wc-subscriptions-switcher.php:408 +msgid "" +"When switching to a subscription with a sign up fee, you can require the " +"customer pay only the gap between the existing subscription's sign up fee " +"and the new subscription's sign up fee (if any)." +msgstr "" +"Lors du passage à un abonnement avec des frais d’inscription, vous pouvez " +"demander au client de ne payer que l’écart entre les frais d’inscription de " +"l’abonnement existant et ceux du nouvel abonnement (le cas échéant)." + +#: includes/class-wc-subscriptions-switcher.php:407 +msgid "Prorate Sign up Fee" +msgstr "Frais d’inscription au prorata" + +#: includes/class-wc-subscriptions-switcher.php:401 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of All Subscription Products" +msgstr "" +"Pour les mises à niveau et les rétrogradations de tous les produits " +"d’abonnement" + +#: includes/class-wc-subscriptions-switcher.php:400 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of Virtual Subscription Products Only" +msgstr "" +"Pour les mises à niveau et les rétrogradations des produits d’abonnement " +"virtuels uniquement" + +#: includes/class-wc-subscriptions-switcher.php:399 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of All Subscription Products" +msgstr "Pour les mises à niveau de tous les produits d’abonnement" + +#: includes/class-wc-subscriptions-switcher.php:398 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of Virtual Subscription Products Only" +msgstr "Pour les mises à niveau des produits d’abonnement virtuels uniquement" + +#: includes/class-wc-subscriptions-switcher.php:390 +msgid "" +"When switching to a subscription with a different recurring payment or " +"billing period, should the price paid for the existing billing period be " +"prorated when switching to the new subscription?" +msgstr "" +"Lors du passage à un abonnement avec une période de paiement ou de " +"facturation récurrente différente, le prix payé pour la période de " +"facturation existante doit-il être calculé au prorata lors du passage au " +"nouvel abonnement ?" + +#: includes/class-wc-subscriptions-switcher.php:389 +msgid "Prorate Recurring Payment" +msgstr "Paiement récurrent au prorata" + +#: includes/class-wc-subscriptions-switcher.php:490 +msgctxt "when to allow switching" +msgid "Between Grouped Subscriptions" +msgstr "Entre des abonnements groupés" + +#: includes/class-wc-subscriptions-switcher.php:486 +msgctxt "when to allow switching" +msgid "Between Subscription Variations" +msgstr "Entre des variantes d’abonnement" + +#: includes/class-wc-subscriptions-switcher.php:397 +#: includes/class-wc-subscriptions-switcher.php:431 +msgctxt "when to allow a setting" +msgid "Never" +msgstr "Jamais" + +#: includes/class-wc-subscriptions-switcher.php:479 +msgid "Allow Switching" +msgstr "Autoriser le changement" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-switcher.php:379 +msgid "" +"Allow subscribers to switch (upgrade or downgrade) between different " +"subscriptions. %1$sLearn more%2$s." +msgstr "" +"Autorisez les abonnés à basculer (mettre à niveau ou rétrograder) entre " +"différents abonnements. %1$sEn savoir plus%2$s." + +#: includes/class-wc-subscriptions-switcher.php:376 +msgid "Switching" +msgstr "Changement" + +#. translators: 1$: is the "You have already subscribed to this product" +#. notice, 2$-4$: opening/closing link tags, 3$: an order number +#: includes/class-wc-subscriptions-switcher.php:281 +msgid "" +"%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your " +"subscription." +msgstr "" +"%1$s Effectuez le paiement sur la %2$scommande %3$s%4$s pour pouvoir changer " +"votre abonnement." + +#: includes/class-wc-subscriptions-switcher.php:272 +msgid "" +"You have already subscribed to this product and it is limited to one per " +"customer. You can not purchase the product again." +msgstr "" +"Vous êtes déjà abonné à ce produit et il est limité à un par client. Vous ne " +"pouvez pas racheter le produit." + +#: includes/class-wc-subscriptions-switcher.php:230 +#: includes/class-wc-subscriptions-switcher.php:1249 +msgid "" +"Your cart contained an invalid subscription switch request. It has been " +"removed." +msgid_plural "" +"Your cart contained invalid subscription switch requests. They have been " +"removed." +msgstr[0] "" +"Votre panier contenait une demande de changement d’abonnement non valide. " +"Elle a été supprimée." +msgstr[1] "" +"Votre panier contenait des demandes de changement d’abonnement non valides. " +"Elles ont été supprimées." + +#: includes/class-wc-subscriptions-switcher.php:190 +msgid "Choose a new subscription." +msgstr "Choisissez un nouvel abonnement." + +#: includes/class-wc-subscriptions-switcher.php:188 +msgid "" +"You have a subscription to this product. Choosing a new subscription will " +"replace your existing subscription." +msgstr "" +"Vous avez un abonnement à ce produit. Choisir un nouvel abonnement " +"remplacera votre abonnement existant." + +#: includes/class-wc-subscriptions-renewal-order.php:181 +msgid "Subscription renewal orders cannot be cancelled." +msgstr "" +"Les commandes de renouvellement d’abonnement ne peuvent pas être annulées." + +#. translators: placeholder is order ID +#: includes/class-wc-subscriptions-renewal-order.php:161 +msgid "Order %s created to record renewal." +msgstr "Commande %s créée pour enregistrer le renouvellement." + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years +#. for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a +#. $30 sign-up fee"). +#: includes/class-wc-subscriptions-product.php:398 +msgid "%1$s and a %2$s sign-up fee" +msgstr "%1$s et des frais d’inscription de %2$s" + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years +#. for 6 years"), 2$: trial length (e.g.: "with 4 months free trial"). +#: includes/class-wc-subscriptions-product.php:393 +msgid "%1$s with %2$s free trial" +msgstr "%1$s avec un essai gratuit de %2$s" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March +#. 23rd every 3rd year"), 2$: length (e.g. "4 years"). +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March +#. 23rd every 3rd year"), 2$: length (e.g. "4 years") +#: includes/class-wc-subscriptions-product.php:387 +#: includes/wcs-formatting-functions.php:209 +msgid "%1$s for %2$s" +msgstr "%1$s pour %2$s" + +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or +#. "3 months") (e.g. "$15 / month" or "$15 every 2nd month"). +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or +#. "3 months") (e.g. "$15 / month" or "$15 every 2nd month") +#: includes/class-wc-subscriptions-product.php:367 +#: includes/wcs-formatting-functions.php:198 +msgid "%1$s / %2$s" +msgid_plural "%1$s every %2$s" +msgstr[0] "%1$s / %2$s" +msgstr[1] "%1$s chaque %2$s" + +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the +#. month (e.g. "23rd"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the +#. month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: includes/class-wc-subscriptions-product.php:355 +#: includes/wcs-formatting-functions.php:187 +msgid "%1$s on %2$s %3$s every %4$s year" +msgstr "%1$s le %2$s %3$s chaque %4$s année" + +#. translators: 1$: on, 2$: , 3$: each year (e.g. "$15 on +#. March 15th each year"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the +#. month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: includes/class-wc-subscriptions-product.php:347 +#: includes/wcs-formatting-functions.php:178 +msgid "%1$s on %2$s %3$s each year" +msgstr "%1$s le %2$s %3$s chaque année" + +#. translators: 1$: on the, 2$: day of every, 3$: +#. month (e.g. "$10 on the 23rd day of every 2nd month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. +#. "$5 every 23rd of each month") +#: includes/class-wc-subscriptions-product.php:335 +#: includes/wcs-formatting-functions.php:165 +msgid "%1$s on the %2$s day of every %3$s month" +msgstr "%1$s le %2$s jour de chaque %3$s mois" + +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on +#. the last day of every 3rd month"). +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on +#. the last day of every 3rd month") +#: includes/class-wc-subscriptions-product.php:328 +#: includes/wcs-formatting-functions.php:162 +msgid "%1$s on the last day of every %2$s month" +msgstr "%1$s le dernier jour de chaque %2$s mois" + +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. +#. "$5 every 23rd of each month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. +#. "$5 every 23rd of each month") +#: includes/class-wc-subscriptions-product.php:319 +#: includes/wcs-formatting-functions.php:146 +msgid "%1$s on the %2$s of each month" +msgstr "%1$s le %2$s de chaque mois" + +#. translators: placeholder is recurring amount. +#. translators: placeholder is recurring amount +#: includes/class-wc-subscriptions-product.php:315 +#: includes/wcs-formatting-functions.php:143 +msgid "%s on the last day of each month" +msgstr "%s le dernier jour de chaque mois" + +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week +#. (e.g. "$10 every 2nd week on Wednesday"). +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week +#. (e.g. "$10 every 2nd week on Wednesday") +#: includes/class-wc-subscriptions-product.php:304 +#: includes/wcs-formatting-functions.php:125 +msgid "%1$s every %2$s on %3$s" +msgstr "%1$s chaque %2$s le %3$s" + +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 +#. every Wednesday"). +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 +#. every Wednesday") +#. translators: %1$: recurring amount (e.g. "$15"), %2$: subscription period +#. (e.g. "month") (e.g. "$15 every 2nd month") +#: includes/class-wc-subscriptions-product.php:300 +#: includes/wcs-formatting-functions.php:116 +#: includes/wcs-formatting-functions.php:201 +msgid "%1$s every %2$s" +msgstr "%1$s chaque %2$s" + +#: includes/class-wc-subscriptions-order.php:748 +msgctxt "An order type" +msgid "Original" +msgstr "Taille d’origine" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-order.php:386 +msgid "View the status of your subscription in %1$syour account%2$s." +msgid_plural "View the status of your subscriptions in %1$syour account%2$s." +msgstr[0] "Affichez l’état de votre abonnement dans %1$svotre compte%2$s." +msgstr[1] "Affichez l’état de vos abonnements dans %1$svotre compte%2$s." + +#: includes/class-wc-subscriptions-order.php:379 +msgid "Your subscription will be activated when payment clears." +msgid_plural "Your subscriptions will be activated when payment clears." +msgstr[0] "Votre abonnement sera activé une fois le paiement effectué." +msgstr[1] "Vos abonnements seront activés une fois le paiement effectué." + +#: includes/class-wc-subscriptions-manager.php:2310 +msgid "Date Changed" +msgstr "Date de modification" + +#: includes/class-wc-subscriptions-manager.php:2285 +msgid "Please enter all date fields." +msgstr "Veuillez saisir tous les champs de date." + +#: includes/class-wc-subscriptions-manager.php:2281 +msgid "Only store managers can edit payment dates." +msgstr "Seuls les gérants de boutique peuvent modifier les dates de paiement." + +#: includes/class-wc-subscriptions-manager.php:2277 +msgid "Invalid security token, please reload the page and try again." +msgstr "Jeton de sécurité non valide, veuillez recharger la page et réessayer." + +#. translators: placeholder is subscription ID +#: includes/class-wc-subscriptions-manager.php:2186 +msgid "Failed sign-up for subscription %s." +msgstr "Échec de l’inscription pour l’abonnement %s." + +#: includes/class-wc-subscriptions-manager.php:1853 +msgid "Change" +msgstr "Modifier" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, +#. 3$: year input. Change the order if you'd like +#: includes/class-wc-subscriptions-manager.php:1848 +msgid "%1$s%2$s, %3$s" +msgstr "%1$s%2$s, %3$s" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, +#. 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd +#. like +#: includes/class-wc-subscriptions-manager.php:1844 +msgid "%1$s%2$s, %3$s @ %4$s : %5$s" +msgstr "%1$s%2$s, %3$s @ %4$s : %5$s" + +#. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. +#. "Jan") +#: includes/class-wc-subscriptions-manager.php:1831 +msgctxt "used in a select box" +msgid "%1$s-%2$s" +msgstr "%1$s-%2$s" + +#: includes/class-wc-subscriptions-manager.php:567 +msgid "Pending subscription created." +msgstr "Abonnement en attente créé." + +#: includes/class-wc-subscriptions-manager.php:522 +msgid "Error: Unable to add product to created subscription. Please try again." +msgstr "" +"Erreur : Impossible d’ajouter le produit à l’abonnement créé. Veuillez " +"réessayer." + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:426 +msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" +msgstr "" +"Échec du traitement du paiement échoué de l’abonnement pour la commande " +"n°%1$s : %2$s" + +#: includes/class-wc-subscriptions-manager.php:416 +msgid "Subscription sign up failed." +msgstr "Échec de l’inscription à l’abonnement." + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:390 +msgid "Failed to set subscription as expired for order #%1$s: %2$s" +msgstr "" +"Échec du marquage de l’abonnement comme expiré pour la commande n°%1$s : %2$s" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:362 +msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" +msgstr "" +"Échec de l’annulation de l’abonnement après l’annulation de la commande " +"n°%1$s : %2$s" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:334 +msgid "" +"Failed to update subscription status after order #%1$s was put on-hold: %2$s" +msgstr "" +"Échec de la mise à jour de l’état de l’abonnement après la mise en attente " +"de la commande n°%1$s : %2$s" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:306 +msgid "Failed to activate subscription status for order #%1$s: %2$s" +msgstr "" +"Échec de l’activation de l’état de l’abonnement pour la commande n°%1$s: %2$s" + +#: includes/class-wc-subscriptions-coupon.php:479 +msgid "" +"Sorry, this coupon is only valid for subscription products with a sign-up " +"fee." +msgstr "" +"Désolé, ce code promo n’est valide que pour les produits d’abonnement avec " +"des frais d’inscription." + +#: includes/class-wc-subscriptions-coupon.php:468 +msgid "Sorry, this coupon is only valid for subscription products." +msgstr "Désolé, ce code promo n’est valide que pour les produits d’abonnement." + +#: includes/class-wc-subscriptions-coupon.php:463 +msgid "Sorry, this coupon is only valid for new subscriptions." +msgstr "Désolé, ce code promo n’est valide que pour les nouveaux abonnements." + +#: includes/class-wc-subscriptions-coupon.php:457 +msgid "" +"Sorry, this coupon is only valid for an initial payment and the cart does " +"not require an initial payment." +msgstr "" +"Désolé, ce code promo n’est valide que pour un paiement initial et le " +"produit ne nécessite pas de paiement initial." + +#: includes/class-wc-subscriptions-coupon.php:167 +msgid "Recurring Product % Discount" +msgstr "% de remise sur les produits récurrents" + +#: includes/class-wc-subscriptions-coupon.php:166 +msgid "Recurring Product Discount" +msgstr "Remise sur les produits récurrents" + +#: includes/class-wc-subscriptions-coupon.php:165 +msgid "Sign Up Fee % Discount" +msgstr "% de remise sur les frais d’inscription" + +#: includes/class-wc-subscriptions-coupon.php:164 +msgid "Sign Up Fee Discount" +msgstr "Remise sur les frais d’inscription" + +#: includes/class-wc-subscriptions-manager.php:500 +msgid "Error: Unable to create subscription. Please try again." +msgstr "Erreur : Impossible de créer l’abonnement. Veuillez réessayer." + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:225 +msgid "Error %d: Unable to create order. Please try again." +msgstr "Erreur %d : Impossible de créer la commande. Veuillez réessayer." + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:196 +#: includes/class-wc-subscriptions-checkout.php:389 +msgid "Error %d: Unable to create subscription. Please try again." +msgstr "Erreur %d : Impossible de créer l’abonnement. Veuillez réessayer." + +#. translators: 1: old payment title, 2: new payment title. +#: includes/class-wc-subscriptions-change-payment-gateway.php:534 +msgctxt "%1$s: old payment title, %2$s: new payment title" +msgid "" +"Payment method changed from \"%1$s\" to \"%2$s\" by the subscriber from " +"their account page." +msgstr "" +"Le moyen de paiement est passé de « %1$s » à « %2$s » par l’abonné sur sa " +"page de compte." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:340 +msgid "Payment method updated." +msgstr "Moyen de paiement mis à jour." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:259 +msgid "Invalid order." +msgstr "Commande non valide." + +#. translators: placeholder is either empty or "Next payment is due..." +#: includes/class-wc-subscriptions-change-payment-gateway.php:211 +msgid "Choose a new payment method.%s" +msgstr "Choisissez un nouveau moyen de paiement.%s" + +#. translators: placeholder is next payment's date +#: includes/class-wc-subscriptions-change-payment-gateway.php:205 +msgid " Next payment is due %s." +msgstr " Le prochain paiement est dû le %s." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:256 +#: includes/class-wcs-query.php:243 +msgid "The payment method can not be changed for that subscription." +msgstr "Le moyen de paiement ne peut pas être modifié pour cet abonnement." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:253 +#: includes/class-wcs-cart-resubscribe.php:78 +#: includes/class-wcs-cart-resubscribe.php:129 +#: includes/class-wcs-user-change-status-handler.php:111 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:95 +msgid "That doesn't appear to be one of your subscriptions." +msgstr "Cela ne semble pas être l’un de vos abonnements." + +#: includes/api/class-wc-rest-subscriptions-controller.php:293 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:172 +msgid "Invalid subscription id." +msgstr "ID d’abonnement non valide." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:247 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:106 +msgid "There was an error with your request. Please try again." +msgstr "Une erreur est survenue lors de votre demande. Veuillez réessayer." + +#: includes/class-wc-subscriptions-change-payment-gateway.php:181 +msgid "" +"Sorry, this subscription change payment method request is invalid and cannot " +"be processed." +msgstr "" +"Désolé, cette demande de changement de moyen de paiement pour l’abonnement " +"n’est pas valide et ne peut pas être traitée." + +#. translators: placeholder is the display name of the payment method +#: templates/checkout/subscription-receipt.php:37 +msgid "Payment Method: %s" +msgstr "Moyen de paiement : %s" + +#. translators: placeholder is the subscription's next payment date (either +#. human readable or normal date) wrapped in tags +#: templates/checkout/subscription-receipt.php:24 +msgid "Next Payment Date: %s" +msgstr "Date du prochain paiement : %s" + +#: includes/privacy/class-wcs-privacy-exporters.php:77 +msgid "Subscription Number" +msgstr "Numéro d’abonnement" + +#: includes/class-wc-subscriptions-cart.php:2218 +msgid "now" +msgstr "maintenant" + +#: includes/class-wc-subscriptions-cart-validator.php:136 +#: includes/class-wc-subscriptions-cart.php:1542 +msgid "" +"That subscription product can not be added to your cart as it already " +"contains a subscription renewal." +msgstr "" +"Ce produit d’abonnement ne peut pas être ajouté à votre panier car il " +"contient déjà un renouvellement d’abonnement." + +#: includes/class-wc-subscriptions-cart.php:995 +msgid "Please enter a valid postcode/ZIP." +msgstr "Veuillez saisir un code postal valide." + +#. translators: $1: address type (Shipping Address / Billing Address), $2: +#. opening tag, $3: closing tag +#: includes/class-wc-subscriptions-addresses.php:84 +msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" +msgstr "Mettre à jour l’%1$s utilisée pour %2$stous%3$s mes abonnements actifs" + +#: includes/class-wc-subscriptions-addresses.php:71 +msgid "" +"Both the shipping address used for the subscription and your default " +"shipping address for future purchases will be updated." +msgstr "" +"L’adresse de livraison utilisée pour l’abonnement et votre adresse de " +"livraison par défaut pour les achats futurs seront mises à jour." + +#: includes/class-wc-subscriptions-addresses.php:47 +msgid "Change address" +msgstr "Modifier l’adresse" + +#: includes/class-wc-subscription.php:2098 wcs-functions.php:828 +msgid "Payment method meta must be an array." +msgstr "Les métadonnées du moyen de paiement doivent être un tableau." + +#: includes/admin/class-wcs-admin-post-types.php:961 +#: includes/class-wc-subscription.php:2007 +#: includes/class-wcs-change-payment-method-admin.php:168 +msgid "Manual Renewal" +msgstr "Renouvellement manuel" + +#: includes/class-wc-subscription.php:1790 +msgid "Subscription Cancelled: maximum number of failed payments reached." +msgstr "Abonnement annulé : nombre maximal d’échecs de paiement atteint." + +#: includes/class-wc-subscription.php:1785 +msgid "Payment failed." +msgstr "Échec du paiement." + +#. translators: %s: date type (e.g. "trial_end"). +#: includes/class-wc-subscription.php:1334 +msgid "" +"The %s date of a subscription can not be deleted. You must delete the order." +msgstr "" +"La date de %s d’un abonnement ne peut pas être supprimée. Vous devez " +"supprimer la commande." + +#: includes/class-wc-subscription.php:1329 +msgid "The start date of a subscription can not be deleted, only updated." +msgstr "" +"La date de début d’un abonnement ne peut pas être supprimée, uniquement mise " +"à jour." + +#. translators: %s: date type (e.g. "next_payment"). +#: includes/class-wc-subscription.php:2432 +msgid "The %s date must occur after the start date." +msgstr "La date de %s doit être postérieure à la date de début." + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2427 +msgid "The %s date must occur after the trial end date." +msgstr "La date de %s doit être postérieure à la date de fin d’essai." + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2421 +msgid "The %s date must occur after the next payment date." +msgstr "La date de %s doit être postérieure à la date du prochain paiement." + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2416 +msgid "The %s date must occur after the last payment date." +msgstr "La date de %s doit être postérieure à la date du dernier paiement." + +#. translators: placeholder is date type (e.g. "end", "next_payment"...) +#: includes/class-wc-subscription.php:2372 +msgctxt "appears in an error message if date is wrong format" +msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"." +msgstr "Date %s non valide. La date doit être au format : « Y-m-d H:i:s »." + +#: includes/class-wc-subscription.php:2345 +msgid "" +"Invalid data. First parameter has a date that is not in the registered date " +"types." +msgstr "" +"Données non valides. Le premier paramètre a une date qui n’est pas dans les " +"types de date enregistrés." + +#: includes/class-wc-subscription.php:2338 +msgid "Invalid data. First parameter was empty when passed to update_dates()." +msgstr "" +"Données non valides. Le premier paramètre était vide lorsqu’il a été passé à " +"update_dates()." + +#: includes/class-wc-subscription.php:2334 +msgid "Invalid format. First parameter needs to be an array." +msgstr "Format non valide. Le premier paramètre doit être un tableau." + +#: includes/class-wc-subscription.php:1218 +msgctxt "original denotes there is no date to display" +msgid "-" +msgstr "-" + +#: includes/class-wc-subscription.php:1210 +msgid "Not yet ended" +msgstr "Pas encore terminé" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/class-wc-subscription.php:1203 +#: includes/wcs-formatting-functions.php:246 +msgid "%s ago" +msgstr "il y a %s" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/class-wc-subscription.php:1200 +#: includes/class-wc-subscriptions-manager.php:2304 +msgid "In %s" +msgstr "Dans %s" + +#. translators: 1: old subscription status 2: new subscription status +#: includes/class-wc-subscription.php:576 +msgid "Status changed from %1$s to %2$s." +msgstr "État passé de %1$s à %2$s." + +#. translators: %s: subscription status. +#: includes/class-wc-subscription.php:423 +msgid "Unable to change subscription status to \"%s\"." +msgstr "Impossible de modifier l’état d’abonnement sur « %s »." + +#: includes/api/legacy/class-wc-api-subscriptions.php:398 wcs-functions.php:147 +msgid "Invalid subscription billing period given." +msgstr "Période de facturation de l’abonnement donnée non valide." + +#: includes/api/legacy/class-wc-api-subscriptions.php:387 wcs-functions.php:152 +msgid "" +"Invalid subscription billing interval given. Must be an integer greater than " +"0." +msgstr "" +"Intervalle de facturation de l’abonnement donné non valide. Doit être un " +"entier supérieur à 0." + +#. translators: 1$: gateway id, 2$: error message +#: includes/api/legacy/class-wc-api-subscriptions.php:352 +msgid "" +"Subscription payment method could not be set to %1$s and has been set to " +"manual with error message: %2$s" +msgstr "" +"Le moyen de paiement de l’abonnement n’a pas pu être défini sur %1$s et a " +"été défini sur manuel avec le message d’erreur : %2$s" + +#: includes/api/class-wc-rest-subscriptions-controller.php:364 +#: includes/api/legacy/class-wc-api-subscriptions.php:314 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:306 +msgid "" +"Gateway does not support admin changing the payment method on a Subscription." +msgstr "" +"La passerelle ne prend pas en charge la modification par l’administrateur du " +"moyen de paiement sur un abonnement." + +#: includes/api/legacy/class-wc-api-subscriptions.php:248 +msgid "The requested subscription cannot be edited." +msgstr "L’abonnement demandé ne peut pas être modifié." + +#: includes/api/legacy/class-wc-api-subscriptions.php:173 +msgid "You do not have permission to create subscriptions" +msgstr "Vous n’avez pas le droit de créer des abonnements" + +#: includes/api/legacy/class-wc-api-subscriptions.php:124 +msgid "You do not have permission to read the subscriptions count" +msgstr "Vous n’avez pas le droit de lire le comptage des abonnements" + +#: includes/api/legacy/class-wc-api-subscriptions.php:102 wcs-functions.php:178 +msgid "Invalid subscription status given." +msgstr "État d’abonnement donné non valide." + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Error: unable to find timezone of your browser." +msgstr "Erreur : le fuseau horaire de votre navigateur est introuvable." + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Timezone:" +msgstr "Fuseau horaire :" + +#: templates/admin/html-variation-price.php:56 +msgid "Billing Period:" +msgstr "Période de facturation :" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:43 +msgid "Recurring:" +msgstr "Récurrent :" + +#: includes/admin/class-wcs-admin-post-types.php:425 +msgid "Total" +msgstr "Total" + +#: includes/admin/class-wcs-admin-post-types.php:422 +#: includes/admin/meta-boxes/views/html-related-orders-table.php:20 +#: templates/myaccount/my-subscriptions.php:22 +#: templates/myaccount/my-subscriptions.php:37 +#: templates/myaccount/related-orders.php:24 +#: templates/myaccount/related-orders.php:50 +#: templates/myaccount/related-subscriptions.php:22 +#: templates/myaccount/related-subscriptions.php:36 +#: templates/myaccount/subscription-details.php:18 +msgid "Status" +msgstr "État" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:19 +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:776 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:195 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:209 +#: templates/myaccount/related-orders.php:23 +#: templates/myaccount/related-orders.php:47 +msgid "Date" +msgstr "Date" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:18 +msgid "Relationship" +msgstr "Relation" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:17 +#: templates/myaccount/related-orders.php:42 +msgid "Order Number" +msgstr "Numéro de commande" + +#: includes/admin/meta-boxes/views/html-related-orders-row.php:36 +#: includes/admin/meta-boxes/views/html-retries-table.php:47 +msgid "Unpublished" +msgstr "Non publié" + +#. translators: php date format +#: includes/admin/meta-boxes/views/html-related-orders-row.php:33 +#: includes/admin/meta-boxes/views/html-retries-table.php:44 +msgctxt "post date" +msgid "Y/m/d g:i:s A" +msgstr "" +"d/m/Y à G h i mi\n" +" s s" + +#. translators: placeholder is an order number. +#. translators: placeholder is an order ID. +#. translators: %s: order number. +#. translators: %s: order ID. +#: includes/admin/meta-boxes/views/html-related-orders-row.php:21 +#: includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:18 +#: includes/class-wc-subscriptions-renewal-order.php:158 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:309 +#: includes/early-renewal/wcs-early-renewal-functions.php:162 +#: templates/myaccount/my-subscriptions.php:34 +#: templates/myaccount/related-orders.php:44 +#: templates/myaccount/related-subscriptions.php:33 +msgctxt "hash before order number" +msgid "#%s" +msgstr "n°%s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:295 +msgid "Customer's notes about the order" +msgstr "Notes du client à propos de la commande" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "No shipping address set." +msgstr "Aucune adresse de livraison." + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:170 +#: includes/class-wcs-change-payment-method-admin.php:38 +#: includes/class-wcs-change-payment-method-admin.php:51 +msgid "Payment Method" +msgstr "Moyen de paiement" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +msgid "No billing address set." +msgstr "Aucune adresse de facturation." + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:148 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:240 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "Address" +msgstr "Adresse" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:93 +msgid "Subscription status:" +msgstr "État de l’abonnement :" + +#: includes/admin/class-wcs-admin-post-types.php:1114 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:85 +msgid "Search for a customer…" +msgstr "Recherche d’un client…" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:55 +msgid "Customer:" +msgstr "Client :" + +#. translators: placeholder is the ID of the subscription +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:48 +msgctxt "edit subscription header" +msgid "Subscription #%s details" +msgstr "Détails de l’abonnement n°%s" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:93 +msgctxt "relation to order" +msgid "Renewal Order" +msgstr "Commande de renouvellement" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:96 +msgctxt "relation to order" +msgid "Parent Order" +msgstr "Commande parente" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:82 +msgctxt "relation to order" +msgid "Initial Subscription" +msgstr "Abonnement initial" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribed Subscription" +msgstr "Abonnement réabonné" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:77 +msgctxt "relation to order" +msgid "Subscription" +msgstr "Abonnement" + +#: includes/admin/class-wcs-admin-post-types.php:955 +msgid "None" +msgstr "Aucun" + +#: includes/admin/class-wcs-admin-post-types.php:954 +msgid "Any Payment Method" +msgstr "Tout moyen de paiement" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:918 +msgid "Subscription draft updated." +msgstr "Brouillon d’abonnement mis à jour." + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:917 +msgctxt "used in \"Subscription scheduled for \"" +msgid "M j, Y @ G:i" +msgstr "j M Y @ G:i" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:917 +msgid "Subscription scheduled for: %1$s." +msgstr "Abonnement planifié pour : %1$s." + +#: includes/admin/class-wcs-admin-post-types.php:915 +msgid "Subscription submitted." +msgstr "Abonnement envoyé." + +#: includes/admin/class-wcs-admin-post-types.php:914 +msgid "Subscription saved." +msgstr "Abonnement enregistré." + +#. translators: placeholder is previous post title +#: includes/admin/class-wcs-admin-post-types.php:912 +msgctxt "used in post updated messages" +msgid "Subscription restored to revision from %s" +msgstr "Abonnement restauré à la révision à partir de %s" + +#: includes/admin/class-wcs-admin-post-types.php:909 +msgid "Custom field deleted." +msgstr "Champ personnalisé supprimé." + +#: includes/admin/class-wcs-admin-post-types.php:908 +msgid "Custom field updated." +msgstr "Champ personnalisé mis à jour." + +#. translators: placeholder is previous post title +#: includes/admin/class-wcs-admin-post-types.php:907 +#: includes/admin/class-wcs-admin-post-types.php:910 +#: includes/admin/class-wcs-admin-post-types.php:913 +msgid "Subscription updated." +msgstr "Abonnement mis à jour." + +#. translators: %d: item count. +#: includes/admin/class-wcs-admin-post-types.php:590 +msgid "%d item" +msgid_plural "%d items" +msgstr[0] "%d élément" +msgstr[1] "%d éléments" + +#: includes/admin/class-wcs-admin-post-types.php:527 +msgctxt "meaning billing address" +msgid "Billing:" +msgstr "Facturation :" + +#: includes/admin/class-wcs-admin-post-types.php:499 +msgid "Cancel Now" +msgstr "Annuler maintenant" + +#: includes/admin/class-wcs-admin-post-types.php:493 +msgid "Delete this item permanently" +msgstr "Supprimer cet article définitivement" + +#: includes/admin/class-wcs-admin-post-types.php:489 +msgid "Move this item to the Trash" +msgstr "Déplacer cet article vers la corbeille" + +#: includes/admin/class-wcs-admin-post-types.php:487 +#: includes/class-wc-subscriptions-product.php:767 +msgid "Restore" +msgstr "Restaurer" + +#: includes/admin/class-wcs-admin-post-types.php:487 +#: includes/class-wc-subscriptions-product.php:766 +msgid "Restore this item from the Trash" +msgstr "Restaurer cet article depuis la corbeille" + +#: includes/admin/class-wcs-admin-post-types.php:475 +#: includes/admin/class-wcs-admin-post-types.php:493 +msgid "Delete Permanently" +msgstr "Supprimer définitivement" + +#: includes/admin/class-wcs-admin-post-types.php:474 +#: includes/admin/class-wcs-admin-post-types.php:489 +msgid "Trash" +msgstr "Corbeille" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:367 +msgid "Cancel" +msgstr "Annuler" + +#: includes/admin/class-wcs-admin-post-types.php:472 +#: includes/wcs-user-functions.php:333 +msgid "Suspend" +msgstr "Suspendre" + +#: includes/admin/class-wcs-admin-post-types.php:471 +#: includes/wcs-user-functions.php:338 +msgid "Reactivate" +msgstr "Réactiver" + +#. translators: 1$: is the number of subscriptions not updated, 2$: is the +#. error message +#: includes/admin/class-wcs-admin-post-types.php:398 +msgid "%1$s subscription could not be updated: %2$s" +msgid_plural "%1$s subscriptions could not be updated: %2$s" +msgstr[0] "%1$s abonnement n’a pas pu être mis à jour : %2$s" +msgstr[1] "%1$s abonnements n’ont pas pu être mis à jour : %2$s" + +#. translators: placeholder is the number of subscriptions updated +#: includes/admin/class-wcs-admin-post-types.php:391 +msgid "%s subscription status changed." +msgid_plural "%s subscription statuses changed." +msgstr[0] "%s état d’abonnement modifié." +msgstr[1] "%s états d’abonnement modifiés." + +#: includes/admin/class-wcs-admin-post-types.php:259 +msgctxt "an action on a subscription" +msgid "Put on-hold" +msgstr "Mettre en attente" + +#: includes/admin/class-wcs-admin-post-types.php:214 +msgid "Search for a product…" +msgstr "Rechercher un produit…" + +#: includes/admin/class-wcs-admin-meta-boxes.php:211 +msgid "Create pending renewal order requested by admin action." +msgstr "" +"Créez une commande de renouvellement en attente demandée par une action de " +"l’administrateur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:200 +msgid "Process renewal order action requested by admin." +msgstr "" +"Traitez l’action de commande de renouvellement demandée par l’administrateur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:181 +msgid "Create pending renewal order" +msgstr "Créer une commande de renouvellement en attente" + +#: includes/admin/class-wcs-admin-meta-boxes.php:177 +msgid "Process renewal" +msgstr "Traiter le renouvellement" + +#: includes/admin/class-wcs-admin-meta-boxes.php:130 +msgid "" +"Are you sure you want to process a renewal?\n" +"\n" +"This will charge the customer and email them the renewal order (if emails " +"are enabled)." +msgstr "" +"Voulez-vous vraiment traiter un renouvellement ?\n" +"\n" +"Cela facturera le client et lui enverra la commande de renouvellement par e-" +"mail (si les e-mails sont activés)." + +#: includes/admin/class-wcs-admin-meta-boxes.php:129 +msgid "Please enter a date after the next payment." +msgstr "Veuillez saisir une date après le prochain paiement." + +#: includes/admin/class-wcs-admin-meta-boxes.php:128 +msgid "Please enter a date before the next payment." +msgstr "Veuillez saisir une date avant le prochain paiement." + +#: includes/admin/class-wcs-admin-meta-boxes.php:126 +#: includes/admin/class-wcs-admin-meta-boxes.php:127 +msgid "Please enter a date after the start date." +msgstr "Veuillez saisir une date après la date de début." + +#: includes/admin/class-wcs-admin-meta-boxes.php:125 +msgid "Please enter a date after the trial end." +msgstr "Veuillez saisir une date après la fin de l’essai." + +#: includes/admin/class-wcs-admin-meta-boxes.php:124 +msgid "Please enter a date at least one hour into the future." +msgstr "Veuillez saisir une date au moins une heure dans le futur." + +#: includes/admin/class-wcs-admin-meta-boxes.php:123 +msgid "Please enter a start date in the past." +msgstr "Veuillez saisir une date de début dans le passé." + +#: includes/admin/class-wcs-admin-meta-boxes.php:73 +msgctxt "meta box title" +msgid "Subscription Data" +msgstr "Données d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:1791 +msgid "" +"Supports automatic renewal payments with the WooCommerce Subscriptions " +"extension." +msgstr "" +"Prend en charge les paiements de renouvellement automatiques avec " +"l’extension WooCommerce Subscriptions." + +#: includes/admin/class-wc-subscriptions-admin.php:1760 +msgid "Automatic Recurring Payments" +msgstr "Paiements récurrents automatiques" + +#: includes/admin/class-wc-subscriptions-admin.php:1730 +#: includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to live site" +msgid "Live" +msgstr "En direct" + +#: includes/admin/class-wc-subscriptions-admin.php:1730 +#: includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to staging site" +msgid "Staging" +msgstr "Préproduction" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:933 +msgid "Subscriptions Ended" +msgstr "Abonnements terminés" + +#: includes/admin/class-wc-subscriptions-admin.php:1724 +#: includes/admin/class-wcs-admin-system-status.php:95 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +msgid "No" +msgstr "Non" + +#: includes/admin/class-wc-subscriptions-admin.php:1724 +#: includes/admin/class-wc-subscriptions-admin.php:1791 +#: includes/admin/class-wcs-admin-system-status.php:95 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +msgid "Yes" +msgstr "Oui" + +#: includes/admin/class-wc-subscriptions-admin.php:1723 +#: includes/admin/class-wcs-admin-system-status.php:93 +msgctxt "label that indicates whether debugging is turned on for the plugin" +msgid "WCS_DEBUG" +msgstr "WCS_DEBUG" + +#. translators: placeholder is a time period (e.g. "4 weeks") +#: includes/admin/class-wc-subscriptions-admin.php:1661 +msgid "The trial period can not exceed %s." +msgstr "La période d’essai ne peut pas dépasser %s." + +#. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years +#: includes/admin/class-wc-subscriptions-admin.php:1656 +msgid "The trial period can not exceed: %1$s, %2$s, %3$s or %4$s." +msgstr "La période d’essai ne peut pas dépasser : %1$s, %2$s, %3$s ou %4$s." + +#. translators: placeholders are opening link tag, ID of sub, and closing link +#. tag +#: includes/admin/class-wc-subscriptions-admin.php:1627 +#: includes/admin/class-wc-subscriptions-admin.php:1632 +msgid "Showing orders for %1$sSubscription %2$s%3$s" +msgstr "Affichage des commandes pour %1$sAbonnement %2$s%3$s" + +#. translators: placeholder is a number +#: includes/admin/class-wc-subscriptions-admin.php:1497 +msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" +msgstr "" +"Nous ne trouvons pas d’abonnement avec l’ID n°%d. Peut-être a-t-il été " +"supprimé ?" + +#: includes/admin/class-wc-subscriptions-admin.php:1414 +#: includes/upgrades/templates/wcs-about-2-0.php:35 +#: includes/upgrades/templates/wcs-about.php:34 +#: woocommerce-subscriptions.php:1148 +msgid "Settings" +msgstr "Réglages" + +#: includes/admin/class-wc-subscriptions-admin.php:1413 +msgid "Add a Subscription Product" +msgstr "Ajouter un produit d’abonnement" + +#. translators: $1-$2: opening and closing tags, $3-$4: opening and +#. closing tags +#: includes/admin/class-wc-subscriptions-admin.php:1395 +msgid "" +"%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou're ready to " +"start selling subscriptions!%4$s" +msgstr "" +"%1$sWooCommerce Subscriptions installé%2$s – %3$sVous êtes prêt à " +"commencer à vendre des abonnements !%4$s" + +#. translators: $1-$2: opening and closing tags. Link to documents->payment +#. gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions +#. shop page +#: includes/admin/class-wc-subscriptions-admin.php:1932 +msgid "" +"Find new gateways that %1$ssupport automatic subscription payments%2$s in " +"the official %3$sWooCommerce Marketplace%4$s." +msgstr "" +"Trouvez de nouvelles passerelles %1$sprenant en charge les paiements " +"d’abonnement automatiques%2$s sur la %3$splace de marché officielle de " +"WooCommerce%4$s." + +#. translators: %s is a line break. +#: includes/admin/class-wc-subscriptions-admin.php:1354 +msgid "" +"Enabling this grants access to new downloadable files added to a product " +"only after the next renewal is processed.%sBy default, access to new " +"downloadable files added to a product is granted immediately to any customer " +"that has an active subscription with that product." +msgstr "" +"L’activation de cette option donne accès aux nouveaux fichiers " +"téléchargeables ajoutés à un produit uniquement après le traitement du " +"prochain renouvellement.%sPar défaut, l’accès aux nouveaux fichiers " +"téléchargeables ajoutés à un produit est accordé immédiatement à tout client " +"disposant d’un abonnement actif avec ce produit." + +#: includes/admin/class-wc-subscriptions-admin.php:1349 +msgid "Enable dripping for downloadable content on subscription products." +msgstr "" +"Activez la diffusion pour le contenu téléchargeable sur les produits " +"d’abonnement." + +#: includes/admin/class-wc-subscriptions-admin.php:1331 +msgid "" +"Allow multiple subscriptions and products to be purchased simultaneously." +msgstr "Autorisez l’achat simultané de plusieurs abonnements et produits." + +#: includes/admin/class-wc-subscriptions-admin.php:1330 +msgid "Mixed Checkout" +msgstr "Validation de commande mixte" + +#: includes/admin/class-wc-subscriptions-admin.php:1326 +msgid "" +"Set a maximum number of times a customer can suspend their account for each " +"billing period. For example, for a value of 3 and a subscription billed " +"yearly, if the customer has suspended their account 3 times, they will not " +"be presented with the option to suspend their account until the next year. " +"Store managers will always be able to suspend an active subscription. Set " +"this to 0 to turn off the customer suspension feature completely." +msgstr "" +"Définissez un nombre maximal de fois qu’un client peut suspendre son compte " +"pour chaque période de facturation. Par exemple, pour une valeur de 3 et un " +"abonnement facturé annuellement, si le client a suspendu son compte 3 fois, " +"il ne se verra pas proposer la possibilité de suspendre son compte jusqu’à " +"l’année suivante. Les gérants de boutique pourront toujours suspendre un " +"abonnement actif. Définissez ce paramètre sur 0 pour désactiver complètement " +"la fonctionnalité de suspension du client." + +#: includes/admin/class-wc-subscriptions-admin.php:1319 +msgid "Customer Suspensions" +msgstr "Suspensions de client" + +#: includes/admin/class-wc-subscriptions-admin.php:1312 +msgctxt "options section heading" +msgid "Miscellaneous" +msgstr "Divers" + +#: includes/admin/class-wc-subscriptions-admin.php:1296 +msgid "Turn off Automatic Payments" +msgstr "Désactiver les paiements automatiques" + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1290 +msgid "" +"With manual renewals, a customer's subscription is put on-hold until they " +"login and pay to renew it. %1$sLearn more%2$s." +msgstr "" +"Avec les renouvellements manuels, l’abonnement d’un client est mis en " +"attente jusqu’à ce qu’il se connecte et paie pour le renouveler. %1$sEn " +"savoir plus%2$s." + +#: includes/admin/class-wc-subscriptions-admin.php:1285 +msgid "Accept Manual Renewals" +msgstr "Accepter les renouvellements manuels" + +#: includes/admin/class-wc-subscriptions-admin.php:1284 +msgid "Manual Renewal Payments" +msgstr "Paiements de renouvellement manuels" + +#: includes/admin/class-wc-subscriptions-admin.php:1277 +msgctxt "option section heading" +msgid "Renewals" +msgstr "Renouvellements" + +#: includes/admin/class-wc-subscriptions-admin.php:1261 +msgid "" +"If a subscriber's subscription is manually cancelled or expires, she will be " +"assigned this role." +msgstr "" +"Si l’abonnement d’un abonné est annulé manuellement ou expire, ce rôle lui " +"sera attribué." + +#: includes/admin/class-wc-subscriptions-admin.php:1260 +msgid "Inactive Subscriber Role" +msgstr "Rôle d’abonné inactif" + +#: includes/admin/class-wc-subscriptions-admin.php:1249 +msgid "" +"When a subscription is activated, either manually or after a successful " +"purchase, new users will be assigned this role." +msgstr "" +"Lorsqu’un abonnement est activé, manuellement ou après un achat réussi, les " +"nouveaux utilisateurs se verront attribuer ce rôle." + +#: includes/admin/class-wc-subscriptions-admin.php:1248 +msgid "Subscriber Default Role" +msgstr "Rôle par défaut des abonnés" + +#. translators: placeholders are tags +#: includes/admin/class-wc-subscriptions-admin.php:1243 +msgid "" +"Choose the default roles to assign to active and inactive subscribers. For " +"record keeping purposes, a user account must be created for subscribers. " +"Users with the %1$sadministrator%2$s role, such as yourself, will never be " +"allocated these roles to prevent locking out administrators." +msgstr "" +"Choisissez les rôles par défaut à attribuer aux abonnés actifs et inactifs. " +"À des fins de tenue de rapports, un compte d’utilisateur doit être créé pour " +"les abonnés. Les utilisateurs avec le rôle %1$sadministrateur%2$s, comme " +"vous-même, ne se verront jamais attribuer ces rôles pour éviter le blocage " +"des administrateurs." + +#: includes/admin/class-wc-subscriptions-admin.php:1240 +msgid "Roles" +msgstr "Rôles" + +#: includes/admin/class-wc-subscriptions-admin.php:1224 +msgid "" +"Use this field to customise the text displayed on the checkout button when " +"an order contains a subscription. Normally the checkout submission button " +"displays \"Place order\". When the cart contains a subscription, this is " +"changed to \"Sign up now\"." +msgstr "" +"Utilisez ce champ pour personnaliser le libellé affiché sur le bouton de " +"paiement lorsqu’une commande contient un abonnement. Normalement, le bouton " +"d’envoi de la validation de commande affiche « Passer la commande ». Lorsque " +"le panier contient un abonnement, celui-ci devient « Inscription »." + +#: includes/admin/class-wc-subscriptions-admin.php:1223 +msgid "Place Order Button Text" +msgstr "Libellé du bouton Passer la commande" + +#: includes/admin/class-wc-subscriptions-admin.php:1216 +#: includes/admin/class-wc-subscriptions-admin.php:1219 +#: includes/admin/class-wc-subscriptions-admin.php:1228 +#: includes/admin/class-wc-subscriptions-admin.php:1231 +#: includes/class-wc-product-subscription-variation.php:98 +#: includes/class-wc-product-variable-subscription.php:73 +#: includes/class-wc-subscriptions-product.php:1196 +#: includes/class-wc-subscriptions-product.php:1214 +#: woocommerce-subscriptions.php:606 +msgid "Sign up now" +msgstr "Inscription" + +#: includes/admin/class-wc-subscriptions-admin.php:1212 +msgid "" +"A product displays a button with the text \"Add to cart\". By default, a " +"subscription changes this to \"Sign up now\". You can customise the button " +"text for subscriptions here." +msgstr "" +"Un produit affiche un bouton avec le libellé « Ajouter au panier ». Par " +"défaut, un abonnement remplace ce libellé par « Inscription ». Vous pouvez " +"personnaliser le libellé du bouton pour les abonnements ici." + +#: includes/admin/class-wc-subscriptions-admin.php:1211 +msgid "Add to Cart Button Text" +msgstr "Libellé du bouton Ajouter au panier" + +#: includes/admin/class-wc-subscriptions-admin.php:1204 +msgid "Button Text" +msgstr "Libellé du bouton" + +#: includes/admin/class-wc-subscriptions-admin.php:1012 +#: includes/admin/class-wc-subscriptions-admin.php:1164 +#: includes/admin/class-wcs-admin-reports.php:46 +#: includes/admin/class-wcs-admin-system-status.php:56 +#: includes/admin/class-wcs-wc-admin-manager.php:38 +#: includes/admin/class-wcs-wc-admin-manager.php:80 +#: includes/admin/class-wcs-wc-admin-manager.php:92 +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:917 +#: includes/class-wcs-query.php:108 includes/class-wcs-query.php:133 +#: includes/class-wcs-query.php:287 +#: includes/privacy/class-wcs-privacy-exporters.php:51 +#: woocommerce-subscriptions.php:266 woocommerce-subscriptions.php:279 +msgid "Subscriptions" +msgstr "Abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:990 +#: woocommerce-subscriptions.php:275 +msgid "Search Subscriptions" +msgstr "Rechercher des abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:986 +msgid "Manage Subscriptions" +msgstr "Gérer les abonnements" + +#: includes/admin/class-wc-subscriptions-admin.php:943 +msgid "Active subscriber?" +msgstr "Abonné actif ?" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: +#. "

    ", 3$: "

    ", 4$: "

    " +#: includes/admin/class-wc-subscriptions-admin.php:888 +msgctxt "" +"used in admin pointer script params in javascript as price pointer content" +msgid "" +"%1$sSet a Price%2$s%3$sSubscription prices are a little different to other " +"product prices. For a subscription, you can set a billing period, length, " +"sign-up fee and free trial.%4$s" +msgstr "" +"%1$sDéfinir un prix%2$s%3$sLes prix d’abonnement sont un peu différents des " +"prix des autres produits. Pour un abonnement, vous pouvez définir une " +"période de facturation, une durée, des frais d’inscription et un essai " +"gratuit.%4$s" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: +#. "

    ", 3$: "

    ", 4$: "", 5$: "", 6$: "", 7$: "", 8$: +#. "

    " +#: includes/admin/class-wc-subscriptions-admin.php:886 +msgctxt "" +"used in admin pointer script params in javascript as type pointer content" +msgid "" +"%1$sChoose Subscription%2$s%3$sThe WooCommerce Subscriptions extension adds " +"two new subscription product types - %4$sSimple subscription%5$s and " +"%6$sVariable subscription%7$s.%8$s" +msgstr "" +"%1$sChoisir l’abonnement%2$s%3$sL’extension WooCommerce Subscriptions ajoute " +"deux nouveaux types de produit d’abonnement : %4$sAbonnement simple%5$s et " +"%6$sAbonnement variable%7$s.%8$s" + +#: includes/admin/class-wc-subscriptions-admin.php:857 +msgid "" +"You are deleting a subscription item. You will also need to manually cancel " +"and trash the subscription on the Manage Subscriptions screen." +msgstr "" +"Vous supprimez un article d’abonnement. Vous devrez également annuler et " +"supprimer manuellement l’abonnement sur l’écran Gérer les abonnements." + +#: includes/admin/class-wc-subscriptions-admin.php:856 +msgid "" +"WARNING: Bad things are about to happen!\n" +"\n" +"The payment gateway used to purchase this subscription does not support " +"modifying a subscription's details.\n" +"\n" +"Changes to the billing period, recurring discount, recurring tax or " +"recurring total may not be reflected in the amount charged by the payment " +"gateway." +msgstr "" +"ATTENTION : De mauvaises choses sont sur le point d’arriver !\n" +"\n" +"La passerelle de paiement utilisée pour acheter cet abonnement ne prend pas " +"en charge la modification des détails d’un abonnement.\n" +"\n" +"Les modifications de la période de facturation, de la remise récurrente, des " +"taxes récurrentes ou du total récurrent peuvent ne pas être reflétées dans " +"le montant facturé par la passerelle de paiement." + +#: includes/admin/class-wc-subscriptions-admin.php:820 +msgid "" +"Trashing this order will also trash the subscriptions purchased with the " +"order." +msgstr "" +"Le déplacement de cette commande vers la corbeille entraînera également le " +"déplacement vers la corbeille des abonnements achetés avec la commande." + +#: includes/admin/class-wc-subscriptions-admin.php:843 +msgid "" +"You are about to trash one or more orders which contain a subscription.\n" +"\n" +"Trashing the orders will also trash the subscriptions purchased with these " +"orders." +msgstr "" +"Vous êtes sur le point de déplacer vers la corbeille une ou plusieurs " +"commandes contenant un abonnement.\n" +"\n" +"Le déplacement des commandes vers la corbeille entraînera également le " +"déplacement vers la corbeille des abonnements achetés avec ces commandes." + +#: includes/admin/class-wc-subscriptions-admin.php:835 +msgid "" +"Enter a new interval as a single number (e.g. to charge every 2nd month, " +"enter 2):" +msgstr "" +"Saisir un nouvel intervalle sous forme de nombre unique (par ex. pour " +"facturer tous les 2 mois, saisissez 2) :" + +#: includes/admin/class-wc-subscriptions-admin.php:834 +msgid "Enter a new length (e.g. 5):" +msgstr "Saisir une nouvelle durée (par ex. 5) :" + +#: includes/admin/class-wc-subscriptions-admin.php:833 +msgid "Enter the new period, either day, week, month or year:" +msgstr "Saisir la nouvelle période, soit jour, semaine, mois ou année :" + +#: includes/admin/class-wc-subscriptions-admin.php:453 +msgid "Free trial period" +msgstr "Période d’essai gratuit" + +#: includes/admin/class-wc-subscriptions-admin.php:452 +msgid "Free trial length" +msgstr "Durée de l’essai gratuit" + +#: includes/admin/class-wc-subscriptions-admin.php:312 +#: includes/admin/class-wc-subscriptions-admin.php:450 +msgid "Subscription period" +msgstr "Période d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:449 +msgid "Subscription billing interval" +msgstr "Intervalle de facturation de l’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:448 +msgid "Subscription sign-up fee" +msgstr "Frais d’inscription de l’abonnement" + +#: includes/upgrades/templates/wcs-about.php:115 +msgid "Subscription Gifting" +msgstr "Offre d’abonnement" + +#: includes/class-wcs-limiter.php:52 +msgid "Limit to one of any status" +msgstr "Limiter à un avec n’importe quel état" + +#: includes/class-wcs-limiter.php:51 +msgid "Limit to one active subscription" +msgstr "Limiter à un abonnement actif" + +#: includes/class-wcs-limiter.php:50 +msgid "Do not limit" +msgstr "Ne pas limiter" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wcs-limiter.php:48 +msgid "" +"Only allow a customer to have one subscription to this product. %1$sLearn " +"more%2$s." +msgstr "" +"Autorisez un client à n’avoir qu’un seul abonnement à ce produit. %1$sEn " +"savoir plus%2$s." + +#: includes/class-wcs-limiter.php:46 +msgid "Limit subscription" +msgstr "Limiter l’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:390 +msgid "" +"Shipping for subscription products is normally charged on the initial order " +"and all renewal orders. Enable this to only charge shipping once on the " +"initial order. Note: for this setting to be enabled the subscription must " +"not have a free trial or a synced renewal date." +msgstr "" +"La livraison des produits d’abonnement est normalement facturée sur la " +"commande initiale et toutes les commandes de renouvellement. Activez cette " +"option pour ne facturer les frais d’expédition qu’une seule fois sur la " +"commande initiale. Remarque : pour que ce paramètre soit activé, " +"l’abonnement ne doit pas avoir d’essai gratuit ni de date de renouvellement " +"synchronisée." + +#: includes/admin/class-wc-subscriptions-admin.php:389 +msgid "One time shipping" +msgstr "Livraison unique" + +#: includes/admin/class-wc-subscriptions-admin.php:357 +#: templates/admin/deprecated/html-variation-price.php:115 +msgid "Subscription Trial Period" +msgstr "Période d’essai d’abonnement" + +#: templates/admin/deprecated/html-variation-price.php:97 +#: templates/admin/deprecated/html-variation-price.php:104 +msgid "Free Trial" +msgstr "Essai gratuit" + +#: includes/admin/class-wc-subscriptions-admin.php:342 +msgid "" +"Optionally include an amount to be charged at the outset of the subscription." +" The sign-up fee will be charged immediately, even if the product has a free " +"trial or the payment dates are synced." +msgstr "" +"Incluez éventuellement un montant à facturer au début de l’abonnement. Les " +"frais d’inscription seront facturés immédiatement, même si le produit a un " +"essai gratuit ou si les dates de paiement sont synchronisées." + +#. translators: %s is a currency symbol / code +#. translators: placeholder is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:341 +#: templates/admin/deprecated/html-variation-price.php:31 +#: templates/admin/deprecated/html-variation-price.php:86 +#: templates/admin/html-variation-price.php:21 +#: templates/admin/html-variation-price.php:47 +msgctxt "example price" +msgid "e.g. 9.90" +msgstr "par ex. 9,90" + +#: templates/admin/deprecated/html-variation-price.php:85 +msgid "Sign-up Fee (%s)" +msgstr "Frais d’inscription (%s)" + +#: templates/admin/deprecated/html-variation-price.php:69 +msgid "Subscription Length" +msgstr "Durée de l’abonnement" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:34 +#: templates/admin/deprecated/html-variation-price.php:57 +msgid "Billing Period" +msgstr "Période de facturation" + +#: templates/admin/deprecated/html-variation-price.php:46 +msgid "Subscription Periods" +msgstr "Périodes d’abonnement" + +#: includes/admin/class-wc-subscriptions-admin.php:305 +msgctxt "example price" +msgid "e.g. 5.90" +msgstr "par ex. 5,90" + +#. translators: placeholder is a currency symbol / code +#: templates/admin/deprecated/html-variation-price.php:20 +#: templates/admin/deprecated/html-variation-price.php:30 +msgid "Subscription Price (%s)" +msgstr "Prix de l’abonnement (%s)" + +#: includes/admin/class-wc-subscriptions-admin.php:199 +msgid "Variable subscription" +msgstr "Abonnement variable" + +#: includes/admin/class-wc-subscriptions-admin.php:198 +msgid "Simple subscription" +msgstr "Abonnement simple" + +#. Plugin URI of the plugin +msgid "https://www.woocommerce.com/products/woocommerce-subscriptions/" +msgstr "https://www.woocommerce.com/products/woocommerce-subscriptions/" + +#. translators: billing period (e.g. "every week"). +#: includes/class-wc-subscriptions-product.php:377 +msgid "every %s" +msgstr "chaque %s" + +#: includes/admin/class-wc-subscriptions-admin.php:1320 +msgctxt "there's a number immediately in front of this text" +msgid "suspensions per billing period." +msgstr "suspensions par période de facturation." diff --git a/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions.pot b/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions.pot new file mode 100644 index 0000000..7b8eefe --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/languages/woocommerce-subscriptions.pot @@ -0,0 +1,6896 @@ +# Copyright (C) 2021 WooCommerce +# This file is distributed under the same license as the WooCommerce Subscriptions plugin. +msgid "" +msgstr "" +"Project-Id-Version: WooCommerce Subscriptions 3.1.1\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/woocommerce-subscriptions\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"POT-Creation-Date: 2021-05-19T05:09:40+00:00\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"X-Generator: WP-CLI 2.3.0\n" +"X-Domain: woocommerce-subscriptions\n" + +#. Plugin Name of the plugin +#: includes/privacy/class-wcs-privacy.php:40 +msgid "WooCommerce Subscriptions" +msgstr "" + +#. Plugin URI of the plugin +msgid "https://www.woocommerce.com/products/woocommerce-subscriptions/" +msgstr "" + +#. Description of the plugin +msgid "Sell products and services with recurring payments in your WooCommerce Store." +msgstr "" + +#. Author of the plugin +#: includes/admin/class-wcs-admin-reports.php:104 +#: includes/admin/reports/class-wcs-report-cache-manager.php:262 +msgid "WooCommerce" +msgstr "" + +#. Author URI of the plugin +msgid "https://woocommerce.com/" +msgstr "" + +#. translators: 1: relation type, 2: list of valid relation types. +#: includes/abstracts/abstract-wcs-related-order-store.php:148 +msgid "Invalid relation type: %1$s. Order relationship type must be one of: %2$s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:204 +msgid "Simple subscription" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:205 +msgid "Variable subscription" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:226 +msgid "Downloadable" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:227 +msgid "Virtual" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:291 +msgid "Choose the subscription price, billing interval and period." +msgstr "" + +#. translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks") +#: includes/admin/class-wc-subscriptions-admin.php:293 +msgctxt "Trial period field tooltip on Edit Product administration screen" +msgid "An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s" +msgstr "" + +#. translators: %s: currency symbol. +#. translators: placeholder is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:307 +#: templates/admin/html-variation-price.php:44 +msgid "Subscription price (%s)" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:311 +msgctxt "example price" +msgid "e.g. 5.90" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:312 +msgid "Subscription interval" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:318 +#: includes/admin/class-wc-subscriptions-admin.php:456 +msgid "Subscription period" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:333 +#: includes/admin/class-wc-subscriptions-admin.php:457 +#: templates/admin/html-variation-price.php:66 +msgid "Expire after" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:336 +msgid "Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date." +msgstr "" + +#. translators: %s is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:346 +#: templates/admin/html-variation-price.php:20 +msgid "Sign-up fee (%s)" +msgstr "" + +#. translators: %s is a currency symbol / code +#. translators: placeholder is a currency symbol / code +#: includes/admin/class-wc-subscriptions-admin.php:347 +#: templates/admin/deprecated/html-variation-price.php:31 +#: templates/admin/deprecated/html-variation-price.php:86 +#: templates/admin/html-variation-price.php:21 +#: templates/admin/html-variation-price.php:47 +msgctxt "example price" +msgid "e.g. 9.90" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:348 +msgid "Optionally include an amount to be charged at the outset of the subscription. The sign-up fee will be charged immediately, even if the product has a free trial or the payment dates are synced." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:360 +#: includes/class-wc-subscriptions-cart.php:2446 +#: templates/admin/html-variation-price.php:25 +msgid "Free trial" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:363 +#: templates/admin/deprecated/html-variation-price.php:115 +msgid "Subscription Trial Period" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:395 +msgid "One time shipping" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:396 +msgid "Shipping for subscription products is normally charged on the initial order and all renewal orders. Enable this to only charge shipping once on the initial order. Note: for this setting to be enabled the subscription must not have a free trial or a synced renewal date." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:453 +msgid "Subscription pricing" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:454 +msgid "Subscription sign-up fee" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:455 +msgid "Subscription billing interval" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:458 +msgid "Free trial length" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:459 +msgid "Free trial period" +msgstr "" + +#. translators: %s: subscription status. +#: includes/admin/class-wc-subscriptions-admin.php:784 +msgid "Unable to change subscription status to \"%s\". Please assign a customer to the subscription to activate it." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:826 +msgid "Trashing this order will also trash the subscriptions purchased with the order." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:839 +msgid "Enter the new period, either day, week, month or year:" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:840 +msgid "Enter a new length (e.g. 5):" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:841 +msgid "Enter a new interval as a single number (e.g. to charge every 2nd month, enter 2):" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:842 +msgid "Delete all variations without a subscription" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:849 +msgid "" +"You are about to trash one or more orders which contain a subscription.\n" +"\n" +"Trashing the orders will also trash the subscriptions purchased with these orders." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:862 +msgid "" +"WARNING: Bad things are about to happen!\n" +"\n" +"The payment gateway used to purchase this subscription does not support modifying a subscription's details.\n" +"\n" +"Changes to the billing period, recurring discount, recurring tax or recurring total may not be reflected in the amount charged by the payment gateway." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:863 +msgid "You are deleting a subscription item. You will also need to manually cancel and trash the subscription on the Manage Subscriptions screen." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:870 +msgid "" +"Warning: Deleting a user will also delete the user's subscriptions. The user's orders will remain but be reassigned to the 'Guest' user.\n" +"\n" +"Do you want to continue to delete this user and any associated subscriptions?" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:874 +msgid "PayPal Standard has a number of limitations and does not support all subscription features." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:874 +msgid "Because of this, it is not recommended as a payment method for Subscriptions unless it is the only available option for your country." +msgstr "" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: "

    ", 3$: "

    ", 4$: "", 5$: "", 6$: "", 7$: "", 8$: "

    " +#: includes/admin/class-wc-subscriptions-admin.php:892 +msgctxt "used in admin pointer script params in javascript as type pointer content" +msgid "%1$sChoose Subscription%2$s%3$sThe WooCommerce Subscriptions extension adds two new subscription product types - %4$sSimple subscription%5$s and %6$sVariable subscription%7$s.%8$s" +msgstr "" + +#. translators: placeholders are for HTML tags. They are 1$: "

    ", 2$: "

    ", 3$: "

    ", 4$: "

    " +#: includes/admin/class-wc-subscriptions-admin.php:894 +msgctxt "used in admin pointer script params in javascript as price pointer content" +msgid "%1$sSet a Price%2$s%3$sSubscription prices are a little different to other product prices. For a subscription, you can set a billing period, length, sign-up fee and free trial.%4$s" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:949 +msgid "Active subscriber?" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:992 +msgid "Manage Subscriptions" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:996 +#: woocommerce-subscriptions.php:305 +msgid "Search Subscriptions" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1018 +#: includes/admin/class-wc-subscriptions-admin.php:1170 +#: includes/admin/class-wcs-admin-reports.php:46 +#: includes/admin/class-wcs-admin-system-status.php:56 +#: includes/admin/class-wcs-wc-admin-manager.php:38 +#: includes/admin/class-wcs-wc-admin-manager.php:80 +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:917 +#: includes/class-wcs-query.php:108 +#: includes/class-wcs-query.php:133 +#: includes/class-wcs-query.php:287 +#: includes/privacy/class-wcs-privacy-exporters.php:51 +#: woocommerce-subscriptions.php:296 +#: woocommerce-subscriptions.php:309 +msgid "Subscriptions" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1210 +msgid "Button Text" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1217 +msgid "Add to Cart Button Text" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1218 +msgid "A product displays a button with the text \"Add to cart\". By default, a subscription changes this to \"Sign up now\". You can customise the button text for subscriptions here." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1222 +#: includes/admin/class-wc-subscriptions-admin.php:1225 +#: includes/admin/class-wc-subscriptions-admin.php:1234 +#: includes/admin/class-wc-subscriptions-admin.php:1237 +#: includes/class-wc-product-subscription-variation.php:98 +#: includes/class-wc-product-variable-subscription.php:73 +#: includes/class-wc-subscriptions-product.php:1196 +#: includes/class-wc-subscriptions-product.php:1214 +#: woocommerce-subscriptions.php:650 +msgid "Sign up now" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1229 +msgid "Place Order Button Text" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1230 +msgid "Use this field to customise the text displayed on the checkout button when an order contains a subscription. Normally the checkout submission button displays \"Place order\". When the cart contains a subscription, this is changed to \"Sign up now\"." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1246 +msgid "Roles" +msgstr "" + +#. translators: placeholders are tags +#: includes/admin/class-wc-subscriptions-admin.php:1249 +msgid "Choose the default roles to assign to active and inactive subscribers. For record keeping purposes, a user account must be created for subscribers. Users with the %1$sadministrator%2$s role, such as yourself, will never be allocated these roles to prevent locking out administrators." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1254 +msgid "Subscriber Default Role" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1255 +msgid "When a subscription is activated, either manually or after a successful purchase, new users will be assigned this role." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1266 +msgid "Inactive Subscriber Role" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1267 +msgid "If a subscriber's subscription is manually cancelled or expires, she will be assigned this role." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1283 +msgctxt "option section heading" +msgid "Renewals" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1290 +msgid "Manual Renewal Payments" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1291 +msgid "Accept Manual Renewals" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1296 +msgid "With manual renewals, a customer's subscription is put on-hold until they login and pay to renew it. %1$sLearn more%2$s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1302 +msgid "Turn off Automatic Payments" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1307 +msgid "If you don't want new subscription purchases to automatically charge renewal payments, you can turn off automatic payments. Existing automatic subscriptions will continue to charge customers automatically. %1$sLearn more%2$s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1318 +msgctxt "options section heading" +msgid "Miscellaneous" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1325 +msgid "Customer Suspensions" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1326 +msgctxt "there's a number immediately in front of this text" +msgid "suspensions per billing period." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1332 +msgid "Set a maximum number of times a customer can suspend their account for each billing period. For example, for a value of 3 and a subscription billed yearly, if the customer has suspended their account 3 times, they will not be presented with the option to suspend their account until the next year. Store managers will always be able to suspend an active subscription. Set this to 0 to turn off the customer suspension feature completely." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1336 +msgid "Mixed Checkout" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1337 +msgid "Allow multiple subscriptions and products to be purchased simultaneously." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1341 +msgid "Allow a subscription product to be purchased with other products and subscriptions in the same transaction." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1345 +msgid "$0 Initial Checkout" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1346 +msgid "Allow $0 initial checkout without a payment method." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1350 +msgid "Allow a subscription product with a $0 initial payment to be purchased without providing a payment method. The customer will be required to provide a payment method at the end of the initial period to keep the subscription active." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1354 +#: includes/upgrades/templates/wcs-about-2-0.php:108 +msgid "Drip Downloadable Content" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1355 +msgid "Enable dripping for downloadable content on subscription products." +msgstr "" + +#. translators: %s is a line break. +#: includes/admin/class-wc-subscriptions-admin.php:1360 +msgid "Enabling this grants access to new downloadable files added to a product only after the next renewal is processed.%sBy default, access to new downloadable files added to a product is granted immediately to any customer that has an active subscription with that product." +msgstr "" + +#. translators: $1-$2: opening and closing tags, $3-$4: opening and closing tags +#: includes/admin/class-wc-subscriptions-admin.php:1401 +msgid "%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou're ready to start selling subscriptions!%4$s" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1419 +msgid "Add a Subscription Product" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1420 +#: includes/upgrades/templates/wcs-about-2-0.php:35 +#: includes/upgrades/templates/wcs-about.php:34 +#: woocommerce-subscriptions.php:1201 +msgid "Settings" +msgstr "" + +#. translators: placeholder is a number +#: includes/admin/class-wc-subscriptions-admin.php:1503 +msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" +msgstr "" + +#. translators: Placeholders are opening and closing link tags. +#: includes/admin/class-wc-subscriptions-admin.php:1547 +msgid "We weren't able to locate the set of report results you requested. Please regenerate the link from the %1$sSubscription Reports screen%2$s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1601 +msgid "We can't find a paid subscription order for this user." +msgstr "" + +#. translators: placeholders are opening link tag, ID of sub, and closing link tag +#: includes/admin/class-wc-subscriptions-admin.php:1633 +#: includes/admin/class-wc-subscriptions-admin.php:1638 +msgid "Showing orders for %1$sSubscription %2$s%3$s" +msgstr "" + +#. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years +#: includes/admin/class-wc-subscriptions-admin.php:1662 +msgid "The trial period can not exceed: %1$s, %2$s, %3$s or %4$s." +msgstr "" + +#. translators: placeholder is a time period (e.g. "4 weeks") +#: includes/admin/class-wc-subscriptions-admin.php:1667 +msgid "The trial period can not exceed %s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1729 +#: includes/admin/class-wcs-admin-system-status.php:93 +msgctxt "label that indicates whether debugging is turned on for the plugin" +msgid "WCS_DEBUG" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1730 +#: includes/admin/class-wc-subscriptions-admin.php:1797 +#: includes/admin/class-wcs-admin-system-status.php:95 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +msgid "Yes" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1730 +#: includes/admin/class-wcs-admin-system-status.php:95 +#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +msgid "No" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1735 +#: includes/admin/class-wcs-admin-system-status.php:107 +msgctxt "Live or Staging, Label on WooCommerce -> System Status page" +msgid "Subscriptions Mode" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1736 +#: includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to staging site" +msgid "Staging" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1736 +#: includes/admin/class-wcs-admin-system-status.php:109 +msgctxt "refers to live site" +msgid "Live" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1766 +msgid "Automatic Recurring Payments" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1797 +msgid "Supports automatic renewal payments with the WooCommerce Subscriptions extension." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1895 +msgid "Subscription items can no longer be edited." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1899 +msgid "This subscription is no longer editable because the payment gateway does not allow modification of recurring amounts." +msgstr "" + +#. translators: $1-2: opening and closing tags of a link that takes to Woo marketplace / Stripe product page +#: includes/admin/class-wc-subscriptions-admin.php:1918 +msgid "No payment gateways capable of processing automatic subscription payments are enabled. If you would like to process automatic payments, we recommend the %1$sfree Stripe extension%2$s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:1923 +msgid "Recurring Payments" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/admin/class-wc-subscriptions-admin.php:1931 +msgid "Payment gateways which don't support automatic recurring payments can be used to process %1$smanual subscription renewal payments%2$s." +msgstr "" + +#. translators: $1-$2: opening and closing tags. Link to documents->payment gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions shop page +#: includes/admin/class-wc-subscriptions-admin.php:1938 +msgid "Find new gateways that %1$ssupport automatic subscription payments%2$s in the official %3$sWooCommerce Marketplace%4$s." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:2042 +msgid "Note that purchasing a subscription still requires an account." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:2056 +msgid "The product type can not be changed because this product is associated with subscriptions." +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:2110 +#: includes/admin/class-wc-subscriptions-admin.php:2111 +msgid "Allow subscription customers to create an account during checkout" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:77 +msgctxt "meta box title" +msgid "Subscription Data" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:79 +msgctxt "meta box title" +msgid "Schedule" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:83 +#: includes/admin/class-wcs-admin-meta-boxes.php:87 +msgid "Related Orders" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:127 +msgid "Please enter a start date in the past." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:128 +msgid "Please enter a date at least 2 minutes into the future." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:128 +msgid "Please enter a date at least one hour into the future." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:129 +msgid "Please enter a date after the trial end." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:130 +#: includes/admin/class-wcs-admin-meta-boxes.php:131 +msgid "Please enter a date after the start date." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:132 +msgid "Please enter a date before the next payment." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:133 +msgid "Please enter a date after the next payment." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:134 +msgid "" +"Are you sure you want to process a renewal?\n" +"\n" +"This will charge the customer and email them the renewal order (if emails are enabled)." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:148 +msgid "" +"Are you sure you want to retry payment for this renewal order?\n" +"\n" +"This will attempt to charge the customer and send renewal order emails (if emails are enabled)." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:181 +msgid "Process renewal" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:185 +msgid "Create pending renewal order" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:187 +msgid "Create pending parent order" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:191 +msgid "Retry Renewal Payment" +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:204 +msgid "Process renewal order action requested by admin." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:215 +msgid "Create pending renewal order requested by admin action." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:257 +msgid "Create pending parent order requested by admin action." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:288 +msgid "Retry renewal payment action requested by admin." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:384 +msgid "This order contains line items with prices above the current product price. To override the product's live price when the customer pays for this order, lock in the manual price increases." +msgstr "" + +#: includes/admin/class-wcs-admin-meta-boxes.php:388 +msgid "Lock manual price increases" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:214 +msgid "Search for a product…" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:258 +msgctxt "an action on a subscription" +msgid "Activate" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:259 +msgctxt "an action on a subscription" +msgid "Put on-hold" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:260 +#: includes/admin/class-wcs-admin-post-types.php:473 +#: includes/class-wc-subscriptions-manager.php:1854 +#: includes/wcs-user-functions.php:354 +#: templates/myaccount/related-orders.php:78 +msgctxt "an action on a subscription" +msgid "Cancel" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:335 +msgctxt "Used in order note. Reason why status changed." +msgid "Subscription status changed by bulk edit:" +msgstr "" + +#. translators: placeholder is the number of subscriptions updated +#: includes/admin/class-wcs-admin-post-types.php:391 +msgid "%s subscription status changed." +msgid_plural "%s subscription statuses changed." +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: is the number of subscriptions not updated, 2$: is the error message +#: includes/admin/class-wcs-admin-post-types.php:398 +msgid "%1$s subscription could not be updated: %2$s" +msgid_plural "%1$s subscriptions could not be updated: %2$s" +msgstr[0] "" +msgstr[1] "" + +#: includes/admin/class-wcs-admin-post-types.php:422 +#: includes/admin/meta-boxes/views/html-related-orders-table.php:20 +#: templates/myaccount/my-subscriptions.php:22 +#: templates/myaccount/my-subscriptions.php:37 +#: templates/myaccount/related-orders.php:24 +#: templates/myaccount/related-orders.php:50 +#: templates/myaccount/related-subscriptions.php:22 +#: templates/myaccount/related-subscriptions.php:36 +#: templates/myaccount/subscription-details.php:18 +msgid "Status" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:423 +#: templates/emails/cancelled-subscription.php:21 +#: templates/emails/expired-subscription.php:21 +#: templates/emails/on-hold-subscription.php:21 +#: templates/myaccount/my-subscriptions.php:21 +#: templates/myaccount/related-subscriptions.php:21 +#: woocommerce-subscriptions.php:297 +msgid "Subscription" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:424 +msgid "Items" +msgstr "" + +#. Translators: %1$s is a date. +#: includes/admin/class-wcs-admin-post-types.php:425 +#: build/index.js:8 +#: build/index.js:14 +msgid "Total" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:426 +msgid "Start Date" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:427 +msgid "Trial End" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:428 +msgid "Next Payment" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:429 +msgid "Last Order Date" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:430 +msgid "End Date" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:431 +msgctxt "number of orders linked to a subscription" +msgid "Orders" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:471 +#: includes/wcs-user-functions.php:338 +msgid "Reactivate" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:472 +#: includes/wcs-user-functions.php:333 +msgid "Suspend" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:474 +#: includes/admin/class-wcs-admin-post-types.php:489 +msgid "Trash" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:475 +#: includes/admin/class-wcs-admin-post-types.php:493 +msgid "Delete Permanently" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:487 +#: includes/class-wc-subscriptions-product.php:766 +msgid "Restore this item from the Trash" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:487 +#: includes/class-wc-subscriptions-product.php:767 +msgid "Restore" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:489 +msgid "Move this item to the Trash" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:493 +msgid "Delete this item permanently" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:499 +msgid "Cancel Now" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:527 +msgctxt "meaning billing address" +msgid "Billing:" +msgstr "" + +#. translators: placeholder is customer's billing email +#: includes/admin/class-wcs-admin-post-types.php:532 +msgid "Email: %s" +msgstr "" + +#. translators: placeholder is customer's billing phone number +#: includes/admin/class-wcs-admin-post-types.php:537 +msgid "Tel: %s" +msgstr "" + +#. translators: $1: is opening link, $2: is subscription order number, $3: is closing link tag, $4: is user's name +#: includes/admin/class-wcs-admin-post-types.php:565 +msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)" +msgid "%1$s#%2$s%3$s for %4$s" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:569 +msgid "Show more details" +msgstr "" + +#. translators: %d: item count. +#: includes/admin/class-wcs-admin-post-types.php:590 +msgid "%d item" +msgid_plural "%d items" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is the display name of a payment gateway a subscription was paid by +#. translators: %s: payment method. +#: includes/admin/class-wcs-admin-post-types.php:609 +#: includes/class-wc-subscription.php:2025 +msgid "Via %s" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:651 +msgid "Y/m/d g:i:s A" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:654 +msgid "This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed." +msgstr "" + +#. translators: placeholder is previous post title +#: includes/admin/class-wcs-admin-post-types.php:907 +#: includes/admin/class-wcs-admin-post-types.php:910 +#: includes/admin/class-wcs-admin-post-types.php:913 +msgid "Subscription updated." +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:908 +msgid "Custom field updated." +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:909 +msgid "Custom field deleted." +msgstr "" + +#. translators: placeholder is previous post title +#: includes/admin/class-wcs-admin-post-types.php:912 +msgctxt "used in post updated messages" +msgid "Subscription restored to revision from %s" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:914 +msgid "Subscription saved." +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:915 +msgid "Subscription submitted." +msgstr "" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:917 +msgid "Subscription scheduled for: %1$s." +msgstr "" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:917 +msgctxt "used in \"Subscription scheduled for \"" +msgid "M j, Y @ G:i" +msgstr "" + +#. translators: php date string +#: includes/admin/class-wcs-admin-post-types.php:918 +msgid "Subscription draft updated." +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:954 +msgid "Any Payment Method" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:955 +msgid "None" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:961 +#: includes/class-wc-subscription.php:2007 +#: includes/class-wcs-change-payment-method-admin.php:168 +msgid "Manual Renewal" +msgstr "" + +#. translators: 1: user display name 2: user ID 3: user email +#: includes/admin/class-wcs-admin-post-types.php:1107 +msgid "%1$s (#%2$s – %3$s)" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:1114 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:85 +msgid "Search for a customer…" +msgstr "" + +#: includes/admin/class-wcs-admin-product-import-export-manager.php:32 +msgid "Subscription variations" +msgstr "" + +#: includes/admin/class-wcs-admin-reports.php:49 +msgid "Subscription Events by Date" +msgstr "" + +#: includes/admin/class-wcs-admin-reports.php:55 +msgid "Upcoming Recurring Revenue" +msgstr "" + +#: includes/admin/class-wcs-admin-reports.php:61 +msgid "Retention Rate" +msgstr "" + +#: includes/admin/class-wcs-admin-reports.php:67 +msgid "Subscriptions by Product" +msgstr "" + +#: includes/admin/class-wcs-admin-reports.php:73 +msgid "Subscriptions by Customer" +msgstr "" + +#: includes/admin/class-wcs-admin-reports.php:83 +msgid "Failed Payment Retries" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:57 +msgid "This section shows any information about Subscriptions." +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:61 +msgid "Store Setup" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:62 +msgid "This section shows general information about the store." +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:66 +msgid "Subscriptions by Payment Gateway" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:67 +msgid "This section shows information about Subscription payment methods." +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:71 +msgid "Payment Gateway Support" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:72 +msgid "This section shows information about payment gateway feature support." +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:119 +msgctxt "Live URL, Label on WooCommerce -> System Status page" +msgid "Subscriptions Live URL" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:135 +msgctxt "label for the system status page" +msgid "Subscriptions Template Theme Overrides" +msgstr "" + +#. translators: placeholders are opening/closing tags linking to documentation on outdated templates. +#: includes/admin/class-wcs-admin-system-status.php:145 +msgid "%1$sLearn how to update%2$s" +msgstr "" + +#. translators: %1$s is the file version, %2$s is the core version +#: includes/admin/class-wcs-admin-system-status.php:191 +msgid "version %1$s is out of date. The core version is %2$s" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:212 +msgctxt "label for the system status page" +msgid "Subscription Statuses" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:233 +msgctxt "label for the system status page" +msgid "WooCommerce Account Connected" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:256 +msgctxt "label for the system status page" +msgid "Active Product Key" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:274 +msgctxt "label for the system status page" +msgid "Other" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:308 +msgctxt "label for the system status page" +msgid "PayPal Reference Transactions Enabled" +msgstr "" + +#: includes/admin/class-wcs-admin-system-status.php:336 +msgctxt "label for the system status page" +msgid "Country / State" +msgstr "" + +#: includes/admin/class-wcs-wc-admin-manager.php:49 +msgid "Add New" +msgstr "" + +#: includes/admin/class-wcs-wc-admin-manager.php:59 +msgid "Edit Subscription" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:77 +msgctxt "relation to order" +msgid "Subscription" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:82 +msgctxt "relation to order" +msgid "Initial Subscription" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:93 +msgctxt "relation to order" +msgid "Renewal Order" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:96 +msgctxt "relation to order" +msgid "Parent Order" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribed Subscription" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99 +msgctxt "relation to order" +msgid "Resubscribe Order" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:102 +msgctxt "relation to order" +msgid "Unknown Order Type" +msgstr "" + +#. translators: placeholder is the ID of the subscription +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:48 +msgctxt "edit subscription header" +msgid "Subscription #%s details" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:52 +msgid "General" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:55 +msgid "Customer:" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:64 +msgid "View other subscriptions →" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:69 +msgid "Profile →" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:93 +msgid "Subscription status:" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:110 +msgid "Parent order: " +msgstr "" + +#. translators: placeholder is an order number. +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:114 +msgid "#%1$s" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:121 +msgid "Parent order:" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:127 +msgid "Select an order…" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 +msgid "Billing" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:138 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:229 +#: includes/payment-retry/class-wcs-retry-post-store.php:40 +msgid "Edit" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:140 +msgid "Load billing address" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:148 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:240 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "Address" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:150 +msgid "No billing address set." +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:170 +#: includes/class-wcs-change-payment-method-admin.php:38 +#: includes/class-wcs-change-payment-method-admin.php:51 +msgid "Payment Method" +msgstr "" + +#. translators: %s: gateway ID. +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:175 +#: includes/class-wcs-change-payment-method-admin.php:53 +msgctxt "The gateway ID displayed on the Edit Subscriptions screen when editing payment method." +msgid "Gateway ID: [%s]" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:212 +msgid "Customer change payment method page →" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:214 +msgid "Customer add payment method page →" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:228 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:256 +#: build/index.js:3 +msgid "Shipping" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:231 +msgid "Load shipping address" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:232 +msgid "Copy billing address" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "No shipping address set." +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:264 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:294 +msgid "Customer Provided Note" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:295 +msgid "Customer's notes about the order" +msgstr "" + +#. translators: %s: parent order number (linked to its details screen). +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:387 +msgctxt "subscription note after linking to a parent order" +msgid "Subscription linked to parent order %s via admin." +msgstr "" + +#. translators: placeholder is error message from the payment gateway or subscriptions when updating the status +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:401 +msgid "Error updating some information: %s" +msgstr "" + +#. translators: placeholder is an order number. +#. translators: placeholder is an order ID. +#. translators: %s: order number. +#. translators: %s: order ID. +#: includes/admin/meta-boxes/views/html-related-orders-row.php:21 +#: includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:18 +#: includes/class-wc-subscriptions-renewal-order.php:158 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:310 +#: includes/early-renewal/wcs-early-renewal-functions.php:162 +#: templates/myaccount/my-subscriptions.php:34 +#: templates/myaccount/related-orders.php:44 +#: templates/myaccount/related-subscriptions.php:33 +msgctxt "hash before order number" +msgid "#%s" +msgstr "" + +#. translators: php date format +#: includes/admin/meta-boxes/views/html-related-orders-row.php:33 +#: includes/admin/meta-boxes/views/html-retries-table.php:44 +msgctxt "post date" +msgid "Y/m/d g:i:s A" +msgstr "" + +#: includes/admin/meta-boxes/views/html-related-orders-row.php:36 +#: includes/admin/meta-boxes/views/html-retries-table.php:47 +msgid "Unpublished" +msgstr "" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:17 +#: templates/myaccount/related-orders.php:42 +msgid "Order Number" +msgstr "" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:18 +msgid "Relationship" +msgstr "" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:19 +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:776 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:195 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:209 +#: templates/myaccount/related-orders.php:23 +#: templates/myaccount/related-orders.php:47 +msgid "Date" +msgstr "" + +#: includes/admin/meta-boxes/views/html-related-orders-table.php:21 +#: templates/myaccount/my-subscriptions.php:24 +#: templates/myaccount/related-orders.php:25 +#: templates/myaccount/related-subscriptions.php:24 +#: templates/myaccount/subscription-totals-table.php:22 +msgctxt "table heading" +msgid "Total" +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:17 +msgid "Retry Date" +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:19 +msgid "Retry Status" +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:20 +msgid "The status of the automatic payment retry: pending means the retry will be processed in the future, failed means the payment was not successful when retried and completed means the payment succeeded when retried." +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:23 +msgid "Status of Order" +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:24 +msgid "The status applied to the order for the time between when the renewal payment failed or last retry occurred and when this retry was processed." +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:27 +msgid "Status of Subscription" +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:28 +msgid "The status applied to the subscription for the time between when the renewal payment failed or last retry occurred and when this retry was processed." +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:31 +msgid "Email" +msgstr "" + +#: includes/admin/meta-boxes/views/html-retries-table.php:32 +msgid "The email sent to the customer when the renewal payment or payment retry failed to notify them that the payment would be retried." +msgstr "" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:23 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:72 +msgid "Payment:" +msgstr "" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:34 +#: templates/admin/deprecated/html-variation-price.php:57 +msgid "Billing Period" +msgstr "" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:43 +msgid "Recurring:" +msgstr "" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Timezone:" +msgstr "" + +#: includes/admin/meta-boxes/views/html-subscription-schedule.php:63 +msgid "Error: unable to find timezone of your browser." +msgstr "" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:265 +msgid "Please note: data for this report is cached. The data displayed may be out of date by up to 24 hours. The cache is updated each morning at 4am in your site's timezone." +msgstr "" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:314 +msgctxt "Whether the Report Cache has been enabled" +msgid "Report Cache Enabled" +msgstr "" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:320 +msgid "Cache Update Failures" +msgstr "" + +#. translators: %d refers to the number of times we have detected cache update failures +#: includes/admin/reports/class-wcs-report-cache-manager.php:323 +msgid "%d failures" +msgid_plural "%d failure" +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:216 +msgid "%2$s%1$s signup%3$s subscription signups this month" +msgid_plural "%2$s%1$s signups%3$s subscription signups this month" +msgstr[0] "" +msgstr[1] "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-dashboard.php:224 +msgid "%s signup revenue this month" +msgstr "" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:232 +msgid "%2$s%1$s renewal%3$s subscription renewals this month" +msgid_plural "%2$s%1$s renewals%3$s subscription renewals this month" +msgstr[0] "" +msgstr[1] "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-dashboard.php:240 +msgid "%s renewal revenue this month" +msgstr "" + +#. translators: 1$: count, 2$ and 3$ are opening and closing strong tags, respectively. +#: includes/admin/reports/class-wcs-report-dashboard.php:248 +msgid "%2$s%1$s cancellation%3$s subscription cancellations this month" +msgid_plural "%2$s%1$s cancellations%3$s subscription cancellations this month" +msgstr[0] "" +msgstr[1] "" + +#: includes/admin/reports/class-wcs-report-retention-rate.php:156 +msgctxt "X axis label on retention rate graph" +msgid "Number of days after sign-up" +msgstr "" + +#: includes/admin/reports/class-wcs-report-retention-rate.php:159 +msgctxt "X axis label on retention rate graph" +msgid "Number of weeks after sign-up" +msgstr "" + +#: includes/admin/reports/class-wcs-report-retention-rate.php:162 +msgctxt "X axis label on retention rate graph" +msgid "Number of months after sign-up" +msgstr "" + +#: includes/admin/reports/class-wcs-report-retention-rate.php:226 +msgid "Unended Subscription Count" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:22 +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:97 +msgid "Customer" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:23 +msgid "Customers" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:32 +msgid "No customers found." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:43 +msgid "Customer Totals" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:44 +msgid "Total Subscribers" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:44 +msgid "The number of unique customers with a subscription of any status other than pending or trashed." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:45 +msgid "Active Subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:45 +msgid "The total number of subscriptions with a status of active or pending cancellation." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:46 +msgid "Total Subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:46 +msgid "The total number of subscriptions with a status other than pending or trashed." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:47 +msgid "Total Subscription Orders" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:47 +msgid "The total number of sign-up, switch and renewal orders placed with your store with a paid status (i.e. processing or complete)." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:48 +msgid "Average Lifetime Value" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:50 +msgid "The average value of all customers' sign-up, switch and renewal orders." +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:99 +msgid "Active Subscriptions %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:99 +msgid "The number of subscriptions this customer has with a status of active or pending cancellation." +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:101 +msgid "Total Subscriptions %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:101 +msgid "The number of subscriptions this customer has with a status other than pending or trashed." +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:103 +msgid "Total Subscription Orders %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:103 +msgid "The number of sign-up, switch and renewal orders this customer has placed with your store with a paid status (i.e. processing or complete)." +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:105 +msgid "Lifetime Value from Subscriptions %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-customer.php:105 +msgid "The total value of this customer's sign-up, switch and renewal orders." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:20 +msgid "Product" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:21 +msgid "Products" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:30 +msgid "No products found." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:89 +msgid "Subscription Product" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:91 +msgid "Subscription Count %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:91 +msgid "The number of subscriptions that include this product as a line item and have a status other than pending or trashed." +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:93 +msgid "Average Recurring Line Total %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:93 +msgid "The average line total for this product on each subscription." +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:95 +msgid "Average Lifetime Value %s" +msgstr "" + +#. translators: %s: help tip. +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:95 +msgid "The average line total on all orders for this product line item." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:300 +#: includes/admin/reports/class-wcs-report-subscription-by-product.php:340 +msgid "subscriptions" +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:488 +msgid "%s signup revenue in this period" +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:489 +msgid "The sum of all subscription parent orders, including other items, fees, tax and shipping." +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:496 +msgid "%s renewal revenue in this period" +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:497 +msgid "The sum of all renewal orders including tax and shipping." +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:504 +msgid "%s resubscribe revenue in this period" +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:505 +msgid "The sum of all resubscribe orders including tax and shipping." +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:512 +msgid "%s switch revenue in this period" +msgstr "" + +#. translators: %s: formatted total amount. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:513 +msgid "The sum of all switch orders including tax and shipping." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:521 +msgid "%2$s %1$s new subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:535 +msgid "The number of subscriptions created during this period, either by being manually created, imported or a customer placing an order. This includes orders pending payment." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:543 +msgid "%2$s %1$s subscription signups" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:557 +msgid "The number of subscriptions purchased in parent orders created during this period. This represents the new subscriptions created by customers placing an order via checkout." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:565 +msgid "%2$s %1$s subscription resubscribes" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:579 +msgid "The number of resubscribe orders processed during this period." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:587 +msgid "%2$s %1$s subscription renewals" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:601 +msgid "The number of renewal orders processed during this period." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:609 +msgid "%2$s %1$s subscription switches" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:623 +msgid "The number of subscriptions upgraded, downgraded or cross-graded during this period." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:631 +msgid "%2$s %1$s subscription cancellations" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:645 +msgid "The number of subscriptions cancelled by the customer or store manager during this period. The pre-paid term may not yet have ended during this period." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:653 +msgid "%2$s %1$s ended subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:667 +msgid "The number of subscriptions which have either expired or reached the end of the prepaid term if it was previously cancelled." +msgstr "" + +#. translators: 2: link opening tag, 1: subscription count and closing tag. +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:678 +msgid "%2$s %1$s current subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:693 +msgid "The number of subscriptions during this period with an end date in the future and a status other than pending." +msgstr "" + +#. translators: %s: subscription net gain (with percentage). +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:710 +msgid "%s net subscription gain" +msgstr "" + +#. translators: %s: subscription net loss (with percentage). +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:713 +msgid "%s net subscription loss" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:718 +msgid "Change in subscriptions between the start and end of the period." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:732 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:159 +msgid "Year" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:733 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:160 +msgid "Last Month" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:734 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:161 +msgid "This Month" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:735 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:162 +msgid "Last 7 Days" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:780 +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:199 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:213 +msgid "Export CSV" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:839 +msgid "Switched subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:855 +msgid "New Subscriptions" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:871 +msgid "Subscriptions signups" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:886 +msgid "Number of resubscribes" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:901 +msgid "Number of renewals" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:933 +msgid "Subscriptions Ended" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:949 +msgid "Cancellations" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:964 +msgid "Signup Totals" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:984 +msgid "Resubscribe Totals" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:1004 +msgid "Renewal Totals" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:1024 +msgid "Switch Totals" +msgstr "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:113 +msgid "%s renewal revenue recovered" +msgstr "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:114 +msgid "The total amount of revenue, including tax and shipping, recovered with the failed payment retry system for renewal orders with a failed payment." +msgstr "" + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:121 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:96 +msgid "%s renewal orders" +msgstr "" + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:122 +msgid "The number of renewal orders which had a failed payment use the retry system." +msgstr "" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:128 +msgid "%s retry attempts succeeded" +msgstr "" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:129 +msgid "The number of renewal payment retries for this period which were able to process the payment which had previously failed one or more times." +msgstr "" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:136 +msgid "%s retry attempts failed" +msgstr "" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:137 +msgid "The number of renewal payment retries for this period which did not result in a successful payment." +msgstr "" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:144 +msgid "%s retry attempts pending" +msgstr "" + +#. translators: %s: retry count. +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:145 +msgid "The number of renewal payment retries not yet processed." +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:247 +msgid "Successful retries" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:263 +msgid "Failed retries" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:279 +msgid "Pending retries" +msgstr "" + +#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:295 +msgid "Recovered Renewal Revenue" +msgstr "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:89 +msgid "%s renewal income in this period" +msgstr "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:90 +msgid "The sum of all the upcoming renewal orders, including items, fees, tax and shipping, for currently active subscriptions." +msgstr "" + +#. translators: %s: renewal count. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:97 +msgid "The number of upcoming renewal orders, for currently active subscriptions." +msgstr "" + +#. translators: %s: formatted amount. +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:103 +msgid "%s average renewal amount" +msgstr "" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:179 +msgid "Next 12 Months" +msgstr "" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:180 +msgid "Next 30 Days" +msgstr "" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:181 +msgid "Next Month" +msgstr "" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:182 +msgid "Next 7 Days" +msgstr "" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:247 +msgid "Renewals count" +msgstr "" + +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:256 +msgid "Renewals amount" +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:34 +#: includes/class-wcs-staging.php:55 +msgid "staging" +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:34 +msgid "live" +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:79 +msgid "Subscriptions." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:85 +msgid "WCS debug constant." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:91 +msgid "Subscriptions Mode" +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:97 +msgid "Subscriptions Live Site URL" +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:104 +msgid "Subscriptions broken down by status." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:113 +msgid "Whether the Report Cache is enabled." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:119 +msgid "Number of report cache failures." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:125 +msgid "Subscriptions by Payment Gateway." +msgstr "" + +#: includes/api/class-wc-rest-subscription-system-status-manager.php:134 +msgid "Payment Gateway Feature Support." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:155 +msgid "Invalid subscription ID." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:161 +msgid "Failed to load subscription object with the ID %d." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:321 +msgid "Subscription dates could not be set. Error message: %s" +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:349 +msgid "Subscription status." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:352 +msgid "Where the subscription was created." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:353 +msgid "Currency the subscription was created with, in ISO format." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:354 +msgid "The date the subscription was created, in the site's timezone." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:355 +msgid "The date the subscription was created, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:356 +msgid "The date the subscription was last modified, in the site's timezone." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:357 +msgid "The date the subscription was last modified, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:358 +msgid "User ID who owns the subscription." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:368 +msgid "The status to transition a subscription to." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:374 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:350 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:508 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:144 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:421 +msgid "The number of billing periods between subscription renewals." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:379 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:355 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:513 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:137 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:414 +msgid "Billing period for the subscription." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:385 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:361 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:519 +msgid "Subscription payment details." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:390 +msgid "Payment method meta and token in a post_meta_key: token format." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:395 +msgid "Payment method meta and token in a user_meta_key : token format." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:402 +msgid "The subscription's start date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:407 +msgid "The subscription's trial date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:412 +msgid "The subscription's next payment date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:417 +msgid "The subscription's cancelled date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:422 +msgid "The subscription's end date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:441 +msgid "Limit result set to subscriptions which have specific statuses." +msgstr "" + +#. translators: placeholder is the payment method ID. +#: includes/api/class-wc-rest-subscriptions-controller.php:485 +msgid "The %s payment gateway does not support admin changing the payment method." +msgstr "" + +#. translators: 1$: gateway id, 2$: error message +#: includes/api/class-wc-rest-subscriptions-controller.php:502 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:407 +msgid "Subscription payment method could not be set to %1$s with error message: %2$s" +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:102 +#: wcs-functions.php:178 +msgid "Invalid subscription status given." +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:124 +msgid "You do not have permission to read the subscriptions count" +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:173 +msgid "You do not have permission to create subscriptions" +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:248 +msgid "The requested subscription cannot be edited." +msgstr "" + +#. translators: placeholder is error message +#: includes/api/legacy/class-wc-api-subscriptions.php:276 +msgctxt "API error message when editing the order failed" +msgid "Edit subscription failed with error: %s" +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:314 +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:306 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:369 +msgid "Gateway does not support admin changing the payment method on a Subscription." +msgstr "" + +#. translators: 1$: gateway id, 2$: error message +#: includes/api/legacy/class-wc-api-subscriptions.php:352 +msgid "Subscription payment method could not be set to %1$s and has been set to manual with error message: %2$s" +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:387 +#: wcs-functions.php:152 +msgid "Invalid subscription billing interval given. Must be an integer greater than 0." +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:398 +#: wcs-functions.php:147 +msgid "Invalid subscription billing period given." +msgstr "" + +#: includes/api/legacy/class-wc-api-subscriptions.php:613 +msgctxt "API response confirming order note deleted from a subscription" +msgid "Permanently deleted subscription note" +msgstr "" + +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:172 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:294 +msgid "Invalid subscription id." +msgstr "" + +#. translators: placeholder is an error message. +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:242 +msgid "Cannot create subscription: %s." +msgstr "" + +#. translators: placeholder is an error message. +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:287 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:477 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:783 +msgid "Updating subscription dates errored with message: %s" +msgstr "" + +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:366 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:524 +msgid "Payment gateway ID." +msgstr "" + +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:373 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:531 +msgid "The subscription's start date." +msgstr "" + +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:378 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:536 +msgid "The subscription's trial date" +msgstr "" + +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:383 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:541 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:408 +msgid "The subscription's next payment date." +msgstr "" + +#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:388 +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:546 +msgid "The subscription's end date." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:185 +msgid "Customer ID is invalid." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:502 +msgid "The status to transition the subscription to. Unlike the \"status\" param, this will calculate and update the subscription dates." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:551 +msgid "The subscription's original subscription ID if this is a resubscribed subscription." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:557 +msgid "The subscription's resubscribed subscription ID." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:563 +msgid "The date the subscription's latest order was completed, in GMT." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:569 +msgid "The date the subscription's latest order was paid, in GMT." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:575 +msgid "Removed line items data." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:582 +msgid "Item ID." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:588 +msgid "Product name." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:594 +msgid "Product SKU." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:600 +msgid "Product ID." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:605 +msgid "Variation ID, if applicable." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:610 +msgid "Quantity ordered." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:615 +msgid "Tax class of product." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:621 +msgid "Product price." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:627 +msgid "Line subtotal (before discounts)." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:632 +msgid "Line subtotal tax (before discounts)." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:637 +msgid "Line total (after discounts)." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:642 +msgid "Line total tax (after discounts)." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:647 +msgid "Line taxes." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:655 +msgid "Tax rate ID." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:661 +msgid "Tax total." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:667 +msgid "Tax subtotal." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:676 +msgid "Removed line item meta data." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:684 +msgid "Meta key." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:690 +msgid "Meta label." +msgstr "" + +#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:696 +msgid "Meta value." +msgstr "" + +#: includes/class-wc-product-subscription.php:73 +msgid "Read more" +msgstr "" + +#. translators: %s: subscription status. +#: includes/class-wc-subscription.php:423 +msgid "Unable to change subscription status to \"%s\"." +msgstr "" + +#. translators: 1: subscription status, 2: error message. +#: includes/class-wc-subscription.php:546 +msgid "Unable to change subscription status to \"%1$s\". Exception: %2$s" +msgstr "" + +#. translators: 1: old subscription status 2: new subscription status +#: includes/class-wc-subscription.php:576 +msgid "Status changed from %1$s to %2$s." +msgstr "" + +#. translators: %s: new order status +#: includes/class-wc-subscription.php:590 +msgid "Status set to %s." +msgstr "" + +#: includes/class-wc-subscription.php:604 +msgid "Error during subscription status transition." +msgstr "" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/class-wc-subscription.php:1200 +#: includes/class-wc-subscriptions-manager.php:2304 +msgid "In %s" +msgstr "" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/class-wc-subscription.php:1203 +#: includes/wcs-formatting-functions.php:246 +msgid "%s ago" +msgstr "" + +#: includes/class-wc-subscription.php:1210 +msgid "Not yet ended" +msgstr "" + +#: includes/class-wc-subscription.php:1213 +msgid "Not cancelled" +msgstr "" + +#: includes/class-wc-subscription.php:1218 +msgctxt "original denotes there is no date to display" +msgid "-" +msgstr "" + +#: includes/class-wc-subscription.php:1326 +msgid "The creation date of a subscription can not be deleted, only updated." +msgstr "" + +#: includes/class-wc-subscription.php:1329 +msgid "The start date of a subscription can not be deleted, only updated." +msgstr "" + +#. translators: %s: date type (e.g. "trial_end"). +#: includes/class-wc-subscription.php:1334 +msgid "The %s date of a subscription can not be deleted. You must delete the order." +msgstr "" + +#. translators: %d: subscription ID. +#. translators: %d: order ID. +#: includes/class-wc-subscription.php:1343 +#: includes/class-wc-subscription.php:2448 +msgid "Subscription #%d: " +msgstr "" + +#: includes/class-wc-subscription.php:1757 +msgid "Payment status marked complete." +msgstr "" + +#: includes/class-wc-subscription.php:1785 +msgid "Payment failed." +msgstr "" + +#: includes/class-wc-subscription.php:1790 +msgid "Subscription Cancelled: maximum number of failed payments reached." +msgstr "" + +#: includes/class-wc-subscription.php:1900 +msgid "The \"all\" value for $order_type parameter is deprecated. It was a misnomer, as it did not return resubscribe orders. It was also inconsistent with order type values accepted by wcs_get_subscription_orders(). Use array( \"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or \"any\" to receive all order types, including switch and resubscribe." +msgstr "" + +#: includes/class-wc-subscription.php:2104 +#: wcs-functions.php:828 +msgid "Payment method meta must be an array." +msgstr "" + +#: includes/class-wc-subscription.php:2340 +msgid "Invalid format. First parameter needs to be an array." +msgstr "" + +#: includes/class-wc-subscription.php:2344 +msgid "Invalid data. First parameter was empty when passed to update_dates()." +msgstr "" + +#: includes/class-wc-subscription.php:2351 +msgid "Invalid data. First parameter has a date that is not in the registered date types." +msgstr "" + +#. translators: placeholder is date type (e.g. "end", "next_payment"...) +#: includes/class-wc-subscription.php:2378 +msgctxt "appears in an error message if date is wrong format" +msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2416 +msgid "The %s date must occur after the cancellation date." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2422 +msgid "The %s date must occur after the last payment date." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2427 +msgid "The %s date must occur after the next payment date." +msgstr "" + +#. translators: %s: date type (e.g. "end"). +#: includes/class-wc-subscription.php:2433 +msgid "The %s date must occur after the trial end date." +msgstr "" + +#. translators: %s: date type (e.g. "next_payment"). +#: includes/class-wc-subscription.php:2438 +msgid "The %s date must occur after the start date." +msgstr "" + +#: includes/class-wc-subscription.php:2468 +#: includes/class-wc-subscriptions-checkout.php:332 +msgid "Backordered" +msgstr "" + +#: includes/class-wc-subscriptions-addresses.php:64 +msgid "Change address" +msgstr "" + +#: includes/class-wc-subscriptions-addresses.php:106 +msgid "Both the shipping address used for the subscription and your default shipping address for future purchases will be updated." +msgstr "" + +#. translators: $1: address type (Shipping Address / Billing Address), $2: opening tag, $3: closing tag +#: includes/class-wc-subscriptions-addresses.php:119 +msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" +msgstr "" + +#. translators: %s: subscription ID. +#. translators: %s: order number. +#. translators: placeholder is a subscription ID. +#: includes/class-wc-subscriptions-addresses.php:243 +#: includes/class-wc-subscriptions-change-payment-gateway.php:763 +#: includes/class-wcs-query.php:101 +msgctxt "hash before order number" +msgid "Subscription #%s" +msgstr "" + +#. translators: %s: address type (eg. 'billing' or 'shipping'). +#: includes/class-wc-subscriptions-addresses.php:249 +msgctxt "change billing or shipping address" +msgid "Change %s address" +msgstr "" + +#: includes/class-wc-subscriptions-cart-validator.php:56 +#: woocommerce-subscriptions.php:560 +msgid "A subscription renewal has been removed from your cart. Multiple subscriptions can not be purchased at the same time." +msgstr "" + +#: includes/class-wc-subscriptions-cart-validator.php:62 +#: woocommerce-subscriptions.php:566 +msgid "A subscription has been removed from your cart. Due to payment gateway restrictions, different subscription products can not be purchased at the same time." +msgstr "" + +#: includes/class-wc-subscriptions-cart-validator.php:68 +#: woocommerce-subscriptions.php:572 +msgid "A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time." +msgstr "" + +#: includes/class-wc-subscriptions-cart-validator.php:111 +msgid "Your cart has been emptied of subscription products. Only one subscription product can be purchased at a time." +msgstr "" + +#: includes/class-wc-subscriptions-cart-validator.php:136 +#: includes/class-wc-subscriptions-cart.php:1506 +msgid "That subscription product can not be added to your cart as it already contains a subscription renewal." +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:486 +msgid "Initial Shipment" +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:936 +msgid "Please enter a valid postcode/ZIP." +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:1172 +msgid "Invalid recurring shipping method." +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:2182 +msgid "now" +msgstr "" + +#. translators: placeholder is a number of days. +#: includes/class-wc-subscriptions-cart.php:2341 +#: includes/wcs-time-functions.php:58 +msgid "%s day" +msgid_plural "%s days" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a number of weeks. +#: includes/class-wc-subscriptions-cart.php:2345 +#: includes/wcs-time-functions.php:60 +msgid "%s week" +msgid_plural "%s weeks" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a number of months. +#: includes/class-wc-subscriptions-cart.php:2349 +#: includes/wcs-time-functions.php:62 +msgid "%s month" +msgid_plural "%s months" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a number of years. +#: includes/class-wc-subscriptions-cart.php:2353 +#: includes/wcs-time-functions.php:64 +msgid "%s year" +msgid_plural "%s years" +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: day of the week (e.g. "every Wednesday"). +#: includes/class-wc-subscriptions-cart.php:2375 +msgid "every %1$s" +msgstr "" + +#. translators: 1$: period, 2$: day of the week (e.g. "every 2nd week on Wednesday"). +#: includes/class-wc-subscriptions-cart.php:2379 +msgid "every %1$s on %2$s" +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:2388 +msgid "on the last day of each month" +msgstr "" + +#. translators: 1$: day of the month (e.g. "23rd") (e.g. "every 23rd of each month"). +#: includes/class-wc-subscriptions-cart.php:2392 +msgid "on the %1$s of each month" +msgstr "" + +#. translators: 1$: interval (e.g. "3rd") (e.g. "on the last day of every 3rd month"). +#: includes/class-wc-subscriptions-cart.php:2400 +msgid "on the last day of every %1$s month" +msgstr "" + +#. translators: on the, 1$: day of every, 2$: month (e.g. "on the 23rd day of every 2nd month"). +#: includes/class-wc-subscriptions-cart.php:2406 +msgid "on the %1$s day of every %2$s month" +msgstr "" + +#. translators: on, 1$: , 2$: each year (e.g. "on March 15th each year"). +#: includes/class-wc-subscriptions-cart.php:2417 +msgid "on %1$s %2$s each year" +msgstr "" + +#. translators: 1$: month (e.g. "March"), 2$: day of the month (e.g. "23rd), 3$: interval year (r.g March 23rd every 2nd year"). +#: includes/class-wc-subscriptions-cart.php:2424 +msgid "on %1$s %2$s every %3$s year" +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:2456 +msgid "Sign up fee" +msgstr "" + +#: includes/class-wc-subscriptions-cart.php:2466 +msgid "Renews" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:181 +msgid "Sorry, this subscription change payment method request is invalid and cannot be processed." +msgstr "" + +#. translators: placeholder is next payment's date +#: includes/class-wc-subscriptions-change-payment-gateway.php:205 +msgid " Next payment is due %s." +msgstr "" + +#. translators: placeholder is either empty or "Next payment is due..." +#: includes/class-wc-subscriptions-change-payment-gateway.php:211 +msgid "Choose a new payment method.%s" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:247 +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:106 +msgid "There was an error with your request. Please try again." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:250 +#: includes/class-wcs-template-loader.php:35 +#: includes/wcs-helper-functions.php:286 +msgid "Invalid Subscription." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:253 +#: includes/class-wcs-cart-resubscribe.php:78 +#: includes/class-wcs-cart-resubscribe.php:129 +#: includes/class-wcs-user-change-status-handler.php:111 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:96 +msgid "That doesn't appear to be one of your subscriptions." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:256 +#: includes/class-wcs-query.php:243 +msgid "The payment method can not be changed for that subscription." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:259 +msgid "Invalid order." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:277 +msgctxt "label on button, imperative" +msgid "Change payment" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:279 +msgctxt "label on button, imperative" +msgid "Add payment" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:340 +msgid "Payment method updated." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:340 +msgid "Payment method added." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:380 +#: includes/class-wc-subscriptions-change-payment-gateway.php:382 +msgid "Payment method updated for all your current subscriptions." +msgstr "" + +#. translators: 1: old payment title, 2: new payment title. +#: includes/class-wc-subscriptions-change-payment-gateway.php:536 +msgctxt "%1$s: old payment title, %2$s: new payment title" +msgid "Payment method changed from \"%1$s\" to \"%2$s\" by the subscriber from their account page." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:547 +msgid "An error occurred updating your subscription's payment method. Please contact us for assistance." +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:555 +msgid "%1$sError:%2$s %3$s" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:731 +#: includes/class-wc-subscriptions-change-payment-gateway.php:769 +msgctxt "the page title of the change payment method form" +msgid "Change payment method" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:733 +#: includes/class-wc-subscriptions-change-payment-gateway.php:774 +msgctxt "the page title of the add payment method form" +msgid "Add payment method" +msgstr "" + +#: includes/class-wc-subscriptions-change-payment-gateway.php:819 +msgid "Please log in to your account below to choose a new payment method for your subscription." +msgstr "" + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:196 +#: includes/class-wc-subscriptions-checkout.php:376 +msgid "Error %d: Unable to create subscription. Please try again." +msgstr "" + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:213 +msgid "Error %d: Unable to add tax to subscription. Please try again." +msgstr "" + +#. translators: placeholder is an internal error number +#: includes/class-wc-subscriptions-checkout.php:225 +msgid "Error %d: Unable to create order. Please try again." +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: includes/class-wc-subscriptions-checkout.php:505 +msgid "Purchasing a subscription product requires an account. Please go to the %1$sMy Account%2$s page to login or register." +msgstr "" + +#. Translators: Placeholders are opening and closing strong and link tags. +#: includes/class-wc-subscriptions-checkout.php:508 +msgid "Purchasing a subscription product requires an account. Please go to the %1$sMy Account%2$s page to login or contact us if you need assistance." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:164 +msgid "Sign Up Fee Discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:165 +msgid "Sign Up Fee % Discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:166 +msgid "Recurring Product Discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:167 +msgid "Recurring Product % Discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:466 +msgid "Sorry, this coupon is only valid for an initial payment and the cart does not require an initial payment." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:472 +msgid "Sorry, this coupon is only valid for new subscriptions." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:477 +msgid "Sorry, this coupon is only valid for subscription products." +msgstr "" + +#. translators: 1$: coupon code that is being removed +#: includes/class-wc-subscriptions-coupon.php:483 +msgid "Sorry, the \"%1$s\" coupon is only valid for renewals." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:488 +msgid "Sorry, this coupon is only valid for subscription products with a sign-up fee." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:514 +msgid "Sorry, recurring coupons can only be applied to subscriptions or subscription orders." +msgstr "" + +#. translators: placeholder is coupon code +#: includes/class-wc-subscriptions-coupon.php:518 +msgid "Sorry, \"%s\" can only be applied to subscription parent orders which contain a product with signup fees." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:521 +msgid "Sorry, only recurring coupons can be applied to subscriptions." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:702 +msgid "Renewal % discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:703 +msgid "Renewal product discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:704 +msgid "Renewal cart discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:705 +msgid "Initial payment discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:722 +msgid "Renewal Discount" +msgstr "" + +#. translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/", %3$d is the length, %4$s is week, month, year +#: includes/class-wc-subscriptions-coupon.php:725 +#: build/index.js:3 +msgid "Discount" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:941 +msgid "Sorry, it seems there are no available payment methods which support the recurring coupon you are using. Please contact us if you require assistance or wish to make alternate arrangements." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:956 +msgid "Active for x payments" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:957 +msgid "Unlimited payments" +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:958 +msgid "Coupon will be limited to the given number of payments. It will then be automatically removed from the subscription. \"Payments\" also includes the initial subscription payment." +msgstr "" + +#. translators: %1$s is the coupon code, %2$d is the number of payment usages +#: includes/class-wc-subscriptions-coupon.php:1055 +msgid "Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d time." +msgid_plural "Limited use coupon \"%1$s\" removed from subscription. It has been used %2$d times." +msgstr[0] "" +msgstr[1] "" + +#. translators: %d refers to the number of payments the coupon can be used for. +#: includes/class-wc-subscriptions-coupon.php:1090 +msgid "Active for %d payment" +msgid_plural "Active for %d payments" +msgstr[0] "" +msgstr[1] "" + +#: includes/class-wc-subscriptions-coupon.php:1094 +msgid "Active for unlimited payments" +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:150 +msgid "Subscription Product length." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:156 +msgid "Subscription Product trial period." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:163 +msgid "Subscription Product trial interval." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:169 +msgid "Subscription Product signup fees." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:175 +msgid "Subscription Product signup fees taxes." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:181 +msgid "Indicates whether this product is being used to resubscribe the customer to an existing, expired subscription." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:190 +msgid "Indicates whether this product a subscription update, downgrade, cross grade or none of the above." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:199 +msgid "Synchronization data for the subscription." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:203 +msgid "Synchronization day if subscription is annual." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:207 +msgid "Synchronization month if subscription is annual." +msgstr "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:262 +msgid "Shipment every %d year" +msgid_plural "Shipment every %d years" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:262 +msgid "Yearly Shipment" +msgstr "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:266 +msgid "Shipment every %d month" +msgid_plural "Shipment every %d months" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:266 +msgid "Monthly Shipment" +msgstr "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:270 +msgid "Shipment every %d week" +msgid_plural "Shipment every %d weeks" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:270 +msgid "Weekly Shipment" +msgstr "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:274 +msgid "Shipment every %d day" +msgid_plural "Shipment every %d days" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d subscription interval. +#: includes/class-wc-subscriptions-extend-store-endpoint.php:274 +msgid "Daily Shipment" +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:402 +msgid "Subscription key" +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:427 +msgid "Subscription length." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:433 +msgid "Cart total amounts provided using the smallest unit of the currency." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:439 +msgid "Total price of items in the cart." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:445 +msgid "Total tax on items in the cart." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:451 +msgid "Total price of any applied fees." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:457 +msgid "Total tax on fees." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:463 +msgid "Total discount from applied coupons." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:469 +msgid "Total tax removed due to discount from applied coupons." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:475 +msgid "Total price of shipping. If shipping has not been calculated, a null response will be sent." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:481 +msgid "Total tax on shipping. If shipping has not been calculated, a null response will be sent." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:487 +msgid "Total price the customer will pay." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:493 +msgid "Total tax applied to items and shipping." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:499 +msgid "Lines of taxes applied to items and shipping." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:507 +msgid "The name of the tax." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:513 +msgid "The amount of tax charged." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:522 +msgid "Currency code (in ISO format) for returned prices." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:528 +msgid "Currency symbol for the currency which can be used to format returned prices." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:534 +msgid "Currency minor unit (number of digits after the decimal separator) for returned prices." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:540 +msgid "Decimal separator for the currency which can be used to format returned prices." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:546 +msgid "Thousand separator for the currency which can be used to format returned prices." +msgstr "" + +#: includes/class-wc-subscriptions-extend-store-endpoint.php:552 +#: includes/class-wc-subscriptions-extend-store-endpoint.php:558 +msgid "Price prefix for the currency which can be used to format returned prices." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:87 +#: includes/class-wc-subscriptions-manager.php:1918 +#: includes/class-wc-subscriptions-manager.php:1936 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Subscription renewal payment due:" +msgstr "" + +#. translators: placeholder is an order note. +#: includes/class-wc-subscriptions-manager.php:124 +msgid "Error: Unable to create renewal order with note \"%s\"" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:134 +msgid "Manual renewal order awaiting customer payment." +msgstr "" + +#. translators: placeholder is a subscription ID. +#. translators: %d: subscription ID. +#: includes/class-wc-subscriptions-manager.php:167 +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:246 +msgid "Subscription doesn't exist in scheduled action: %d" +msgstr "" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:306 +msgid "Failed to activate subscription status for order #%1$s: %2$s" +msgstr "" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:334 +msgid "Failed to update subscription status after order #%1$s was put on-hold: %2$s" +msgstr "" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:362 +msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" +msgstr "" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:390 +msgid "Failed to set subscription as expired for order #%1$s: %2$s" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:416 +msgid "Subscription sign up failed." +msgstr "" + +#. translators: $1: order number, $2: error message +#: includes/class-wc-subscriptions-manager.php:426 +msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:500 +msgid "Error: Unable to create subscription. Please try again." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:522 +msgid "Error: Unable to add product to created subscription. Please try again." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:567 +msgid "Pending subscription created." +msgstr "" + +#. Translators: 1: The subscription ID number. 2: The current user's username. +#: includes/class-wc-subscriptions-manager.php:914 +msgid "The related subscription #%1$s has been deleted after the customer was deleted by %2$s." +msgstr "" + +#. Translators: Placeholder is the subscription ID number. +#: includes/class-wc-subscriptions-manager.php:917 +msgid "The related subscription #%s has been deleted after the customer was deleted." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1063 +#: wcs-functions.php:233 +msgctxt "Subscription status" +msgid "Active" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1066 +#: wcs-functions.php:235 +msgctxt "Subscription status" +msgid "Cancelled" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1069 +#: wcs-functions.php:237 +msgctxt "Subscription status" +msgid "Expired" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1072 +#: wcs-functions.php:232 +msgctxt "Subscription status" +msgid "Pending" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1075 +msgctxt "Subscription status" +msgid "Failed" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1079 +msgctxt "Subscription status" +msgid "On-hold" +msgstr "" + +#. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. "Jan") +#: includes/class-wc-subscriptions-manager.php:1831 +msgctxt "used in a select box" +msgid "%1$s-%2$s" +msgstr "" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd like +#: includes/class-wc-subscriptions-manager.php:1844 +msgid "%1$s%2$s, %3$s @ %4$s : %5$s" +msgstr "" + +#. translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input. Change the order if you'd like +#: includes/class-wc-subscriptions-manager.php:1848 +msgid "%1$s%2$s, %3$s" +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:1853 +msgid "Change" +msgstr "" + +#. translators: placeholder is subscription ID +#: includes/class-wc-subscriptions-manager.php:2186 +msgid "Failed sign-up for subscription %s." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:2277 +msgid "Invalid security token, please reload the page and try again." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:2281 +msgid "Only store managers can edit payment dates." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:2285 +msgid "Please enter all date fields." +msgstr "" + +#: includes/class-wc-subscriptions-manager.php:2310 +msgid "Date Changed" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:379 +msgid "Your subscription will be activated when payment clears." +msgid_plural "Your subscriptions will be activated when payment clears." +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-order.php:386 +msgid "View the status of your subscription in %1$syour account%2$s." +msgid_plural "View the status of your subscriptions in %1$syour account%2$s." +msgstr[0] "" +msgstr[1] "" + +#: includes/class-wc-subscriptions-order.php:449 +msgid "Subscription Relationship" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:469 +msgid "Renewal Order" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:471 +msgid "Resubscribe Order" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:473 +msgid "Parent Order" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:517 +msgid "Payment completed on order after subscription was cancelled." +msgstr "" + +#: includes/class-wc-subscriptions-order.php:745 +msgid "All orders types" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:748 +msgctxt "An order type" +msgid "Original" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:749 +msgctxt "An order type" +msgid "Subscription Parent" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:750 +msgctxt "An order type" +msgid "Subscription Renewal" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:751 +msgctxt "An order type" +msgid "Subscription Resubscribe" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:752 +msgctxt "An order type" +msgid "Subscription Switch" +msgstr "" + +#: includes/class-wc-subscriptions-order.php:753 +msgctxt "An order type" +msgid "Non-subscription" +msgstr "" + +#. translators: $1: opening link tag, $2: order number, $3: closing link tag +#: includes/class-wc-subscriptions-order.php:1056 +msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s." +msgstr "" + +#. translators: %1$s refers to the price. This string is meant to prefix another string below, e.g. "$5 now, and $5 on March 15th each year" +#: includes/class-wc-subscriptions-product.php:291 +msgid "%1$s now, and " +msgstr "" + +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday"). +#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday") +#. translators: %1$: recurring amount (e.g. "$15"), %2$: subscription period (e.g. "month") (e.g. "$15 every 2nd month") +#: includes/class-wc-subscriptions-product.php:300 +#: includes/wcs-formatting-functions.php:116 +#: includes/wcs-formatting-functions.php:201 +msgid "%1$s every %2$s" +msgstr "" + +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday"). +#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday") +#: includes/class-wc-subscriptions-product.php:304 +#: includes/wcs-formatting-functions.php:125 +msgid "%1$s every %2$s on %3$s" +msgstr "" + +#. translators: placeholder is recurring amount. +#. translators: placeholder is recurring amount +#: includes/class-wc-subscriptions-product.php:315 +#: includes/wcs-formatting-functions.php:143 +msgid "%s on the last day of each month" +msgstr "" + +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") +#: includes/class-wc-subscriptions-product.php:319 +#: includes/wcs-formatting-functions.php:146 +msgid "%1$s on the %2$s of each month" +msgstr "" + +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month"). +#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month") +#: includes/class-wc-subscriptions-product.php:328 +#: includes/wcs-formatting-functions.php:162 +msgid "%1$s on the last day of every %2$s month" +msgstr "" + +#. translators: 1$: on the, 2$: day of every, 3$: month (e.g. "$10 on the 23rd day of every 2nd month"). +#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month") +#: includes/class-wc-subscriptions-product.php:335 +#: includes/wcs-formatting-functions.php:165 +msgid "%1$s on the %2$s day of every %3$s month" +msgstr "" + +#. translators: 1$: on, 2$: , 3$: each year (e.g. "$15 on March 15th each year"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: includes/class-wc-subscriptions-product.php:347 +#: includes/wcs-formatting-functions.php:178 +msgid "%1$s on %2$s %3$s each year" +msgstr "" + +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd"). +#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year") +#: includes/class-wc-subscriptions-product.php:355 +#: includes/wcs-formatting-functions.php:187 +msgid "%1$s on %2$s %3$s every %4$s year" +msgstr "" + +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month"). +#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month") +#: includes/class-wc-subscriptions-product.php:367 +#: includes/wcs-formatting-functions.php:198 +msgid "%1$s / %2$s" +msgid_plural "%1$s every %2$s" +msgstr[0] "" +msgstr[1] "" + +#. translators: billing period (e.g. "every week"). +#: includes/class-wc-subscriptions-product.php:377 +msgid "every %s" +msgstr "" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years"). +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years") +#: includes/class-wc-subscriptions-product.php:387 +#: includes/wcs-formatting-functions.php:209 +msgid "%1$s for %2$s" +msgstr "" + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years"), 2$: trial length (e.g.: "with 4 months free trial"). +#: includes/class-wc-subscriptions-product.php:393 +msgid "%1$s with %2$s free trial" +msgstr "" + +#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a $30 sign-up fee"). +#: includes/class-wc-subscriptions-product.php:398 +msgid "%1$s and a %2$s sign-up fee" +msgstr "" + +#: includes/class-wc-subscriptions-product.php:969 +msgid "This variation can not be removed because it is associated with active subscriptions. To remove this variation, please cancel and delete the subscriptions for it." +msgstr "" + +#. translators: placeholder is order ID +#: includes/class-wc-subscriptions-renewal-order.php:161 +msgid "Order %s created to record renewal." +msgstr "" + +#: includes/class-wc-subscriptions-renewal-order.php:181 +msgid "Subscription renewal orders cannot be cancelled." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:195 +msgid "You have a subscription to this product. Choosing a new subscription will replace your existing subscription." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:197 +msgid "Choose a new subscription." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:237 +#: includes/class-wc-subscriptions-switcher.php:1211 +msgid "Your cart contained an invalid subscription switch request. It has been removed." +msgid_plural "Your cart contained invalid subscription switch requests. They have been removed." +msgstr[0] "" +msgstr[1] "" + +#: includes/class-wc-subscriptions-switcher.php:279 +msgid "You have already subscribed to this product and it is limited to one per customer. You can not purchase the product again." +msgstr "" + +#. translators: 1$: is the "You have already subscribed to this product" notice, 2$-4$: opening/closing link tags, 3$: an order number +#: includes/class-wc-subscriptions-switcher.php:288 +msgid "%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your subscription." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:383 +msgid "Switching" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-switcher.php:386 +msgid "Allow subscribers to switch (upgrade or downgrade) between different subscriptions. %1$sLearn more%2$s." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:396 +msgid "Prorate Recurring Payment" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:397 +msgid "When switching to a subscription with a different recurring payment or billing period, should the price paid for the existing billing period be prorated when switching to the new subscription?" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:404 +#: includes/class-wc-subscriptions-switcher.php:438 +msgctxt "when to allow a setting" +msgid "Never" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:405 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of Virtual Subscription Products Only" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:406 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades of All Subscription Products" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:407 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of Virtual Subscription Products Only" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:408 +msgctxt "when to prorate recurring fee when switching" +msgid "For Upgrades & Downgrades of All Subscription Products" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:414 +msgid "Prorate Sign up Fee" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:415 +msgid "When switching to a subscription with a sign up fee, you can require the customer pay only the gap between the existing subscription's sign up fee and the new subscription's sign up fee (if any)." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:422 +msgctxt "when to prorate signup fee when switching" +msgid "Never (do not charge a sign up fee)" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:423 +msgctxt "when to prorate signup fee when switching" +msgid "Never (charge the full sign up fee)" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:424 +msgctxt "when to prorate signup fee when switching" +msgid "Always" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:430 +msgid "Prorate Subscription Length" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:431 +msgid "When switching to a subscription with a length, you can take into account the payments already completed by the customer when determining how many payments the subscriber needs to make for the new subscription." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:439 +#: includes/class-wc-subscriptions-synchroniser.php:235 +msgctxt "when to prorate first payment / subscription length" +msgid "For Virtual Subscription Products Only" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:440 +#: includes/class-wc-subscriptions-synchroniser.php:236 +msgctxt "when to prorate first payment / subscription length" +msgid "For All Subscription Products" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:446 +msgid "Switch Button Text" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:447 +msgid "Customise the text displayed on the button next to the subscription on the subscriber's account page. The default is \"Switch Subscription\", but you may wish to change this to \"Upgrade\" or \"Change Subscription\"." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:451 +#: includes/class-wc-subscriptions-switcher.php:549 +#: includes/class-wc-subscriptions-switcher.php:2592 +msgid "Upgrade or Downgrade" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:486 +msgid "Allow Switching" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:493 +msgctxt "when to allow switching" +msgid "Between Subscription Variations" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:497 +msgctxt "when to allow switching" +msgid "Between Grouped Subscriptions" +msgstr "" + +#. translators: %s: order number. +#: includes/class-wc-subscriptions-switcher.php:1134 +msgid "Switch order cancelled due to a new switch order being created #%s." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1339 +msgid "You can only switch to a subscription product." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1345 +msgid "We can not find your old subscription item." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1367 +msgid "You can not switch to the same subscription." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1414 +msgid "You can not switch this subscription. It appears you do not own the subscription." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1455 +msgid "There was an error locating the switch details." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1817 +msgctxt "a switch type" +msgid "Downgrade" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1820 +msgctxt "a switch type" +msgid "Upgrade" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1823 +msgctxt "a switch type" +msgid "Crossgrade" +msgstr "" + +#. translators: %1: product subtotal, %2: HTML span tag, %3: direction (upgrade, downgrade, crossgrade), %4: closing HTML span tag +#: includes/class-wc-subscriptions-switcher.php:1828 +msgctxt "product subtotal string" +msgid "%1$s %2$s(%3$s)%4$s" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1945 +msgid "The original subscription item being switched cannot be found." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:1947 +msgid "The item on the switch order cannot be found." +msgstr "" + +#. translators: 1$: old item, 2$: new item when switching +#: includes/class-wc-subscriptions-switcher.php:1958 +msgctxt "used in order notes" +msgid "Customer switched from: %1$s to %2$s." +msgstr "" + +#. translators: %s: new item name. +#: includes/class-wc-subscriptions-switcher.php:1961 +msgctxt "used in order notes" +msgid "Customer added %s." +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:2316 +#: includes/class-wc-subscriptions-switcher.php:2869 +msgid "Switch Order" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:2331 +#: includes/class-wc-subscriptions-switcher.php:2884 +msgid "Switched Subscription" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:2549 +msgctxt "add to cart button text while switching a subscription" +msgid "Switch subscription" +msgstr "" + +#: includes/class-wc-subscriptions-switcher.php:2733 +#: wcs-functions.php:236 +msgctxt "Subscription status" +msgid "Switched" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:48 +msgid "Synchronise renewals" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:49 +msgid "Align the payment date for all customers who purchase this subscription to a specific day of the week or month." +msgstr "" + +#. translators: placeholder is a year (e.g. "2016") +#: includes/class-wc-subscriptions-synchroniser.php:51 +msgctxt "used in subscription product edit screen" +msgid "Align the payment date for this subscription to a specific day of the year. If the date has already taken place this year, the first payment will be processed in %s. Set the day to 0 to disable payment syncing for this product." +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:210 +msgid "Synchronisation" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wc-subscriptions-synchroniser.php:213 +msgctxt "used in the general subscription options page" +msgid "Align subscription renewal to a specific day of the week, month or year. For example, the first day of the month. %1$sLearn more%2$s." +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:219 +msgid "Align Subscription Renewal Day" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:226 +msgid "Prorate First Renewal" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:227 +msgid "If a subscription is synchronised to a specific day of the week, month or year, charge a prorated amount for the subscription at the time of sign up." +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:233 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (do not charge any recurring amount)" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:234 +msgctxt "when to prorate first payment / subscription length" +msgid "Never (charge the full recurring amount at sign-up)" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:242 +msgid "Sign-up grace period" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:243 +msgctxt "there's a number immediately in front of this text" +msgid "days prior to Renewal Day" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:247 +msgid "Subscriptions created within this many days prior to the Renewal Day will not be charged at sign-up. Set to zero for all new Subscriptions to be charged the full recurring amount. Must be a positive number." +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:311 +msgid "Month for Synchronisation" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:319 +#: templates/admin/deprecated/html-variation-synchronisation.php:36 +#: templates/admin/html-variation-synchronisation.php:42 +msgctxt "input field placeholder for day field for annual subscriptions" +msgid "Day" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:750 +#: includes/class-wc-subscriptions-synchroniser.php:767 +msgid "Do not synchronise" +msgstr "" + +#. translators: placeholder is a day of the week +#: includes/class-wc-subscriptions-synchroniser.php:775 +msgid "%s each week" +msgstr "" + +#. translators: placeholder is a number of day with language specific suffix applied (e.g. "1st", "3rd", "5th", etc...) +#: includes/class-wc-subscriptions-synchroniser.php:781 +msgid "%s day of the month" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:783 +msgid "Last day of the month" +msgstr "" + +#: includes/class-wc-subscriptions-synchroniser.php:831 +msgid "Today!" +msgstr "" + +#. translators: placeholder is a date +#: includes/class-wc-subscriptions-synchroniser.php:838 +msgid "First payment prorated. Next payment: %s" +msgstr "" + +#. translators: placeholder is a date +#: includes/class-wc-subscriptions-synchroniser.php:841 +msgid "First payment: %s" +msgstr "" + +#: includes/class-wcs-auth.php:39 +msgid "View subscriptions" +msgstr "" + +#: includes/class-wcs-auth.php:42 +msgid "Create subscriptions" +msgstr "" + +#: includes/class-wcs-auth.php:45 +msgid "View and manage subscriptions" +msgstr "" + +#: includes/class-wcs-cached-data-manager.php:79 +msgid "Related order caching is now handled by %1$s." +msgstr "" + +#: includes/class-wcs-cached-data-manager.php:86 +msgid "Customer subscription caching is now handled by %1$s." +msgstr "" + +#: includes/class-wcs-cached-data-manager.php:110 +#: includes/class-wcs-cached-data-manager.php:240 +msgid "Customer subscription caching is now handled by %1$s and %2$s." +msgstr "" + +#: includes/class-wcs-cached-data-manager.php:127 +msgid "new related order methods in WCS_Related_Order_Store" +msgstr "" + +#: includes/class-wcs-cached-data-manager.php:225 +msgid "Weekly" +msgstr "" + +#: includes/class-wcs-cart-initial-payment.php:65 +#: includes/class-wcs-cart-renewal.php:199 +msgid "That doesn't appear to be your order." +msgstr "" + +#: includes/class-wcs-cart-renewal.php:214 +msgid "This order can no longer be paid because the corresponding subscription does not require payment at this time." +msgstr "" + +#: includes/class-wcs-cart-renewal.php:235 +msgid "Complete checkout to renew your subscription." +msgstr "" + +#. translators: placeholder is an item name +#: includes/class-wcs-cart-renewal.php:318 +msgid "The %s product has been deleted and can no longer be renewed. Please choose a new product or contact us for assistance." +msgstr "" + +#. translators: %s is subscription's number +#: includes/class-wcs-cart-renewal.php:353 +msgid "Subscription #%s has not been added to the cart." +msgstr "" + +#. translators: %s is order's number +#: includes/class-wcs-cart-renewal.php:356 +msgid "Order #%s has not been added to the cart." +msgstr "" + +#: includes/class-wcs-cart-renewal.php:395 +msgid "We couldn't find the original subscription for an item in your cart. The item was removed." +msgid_plural "We couldn't find the original subscriptions for items in your cart. The items were removed." +msgstr[0] "" +msgstr[1] "" + +#: includes/class-wcs-cart-renewal.php:402 +msgid "We couldn't find the original renewal order for an item in your cart. The item was removed." +msgid_plural "We couldn't find the original renewal orders for items in your cart. The items were removed." +msgstr[0] "" +msgstr[1] "" + +#: includes/class-wcs-cart-renewal.php:682 +msgid "All linked subscription items have been removed from the cart." +msgstr "" + +#: includes/class-wcs-cart-renewal.php:711 +msgctxt "Used in WooCommerce by removed item notification: \"_All linked subscription items were_ removed. Undo?\" Filter for item title." +msgid "All linked subscription items were" +msgstr "" + +#: includes/class-wcs-cart-renewal.php:1475 +msgctxt "The place order button text while renewing a subscription" +msgid "Renew subscription" +msgstr "" + +#: includes/class-wcs-cart-resubscribe.php:70 +msgid "There was an error with your request to resubscribe. Please try again." +msgstr "" + +#: includes/class-wcs-cart-resubscribe.php:74 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:92 +msgid "That subscription does not exist. Has it been deleted?" +msgstr "" + +#: includes/class-wcs-cart-resubscribe.php:82 +msgid "You can not resubscribe to that subscription. Please contact us if you need assistance." +msgstr "" + +#: includes/class-wcs-cart-resubscribe.php:91 +#: includes/class-wcs-cart-resubscribe.php:119 +msgid "Complete checkout to resubscribe." +msgstr "" + +#. translators: %s: order number. +#: includes/class-wcs-cart-resubscribe.php:320 +msgid "Customer resubscribed in order #%s" +msgstr "" + +#: includes/class-wcs-cart-resubscribe.php:338 +msgctxt "The place order button text while resubscribing to a subscription" +msgid "Resubscribe" +msgstr "" + +#: includes/class-wcs-cart-switch.php:179 +msgctxt "The place order button text while switching a subscription" +msgid "Switch subscription" +msgstr "" + +#: includes/class-wcs-change-payment-method-admin.php:122 +msgid "Please choose a valid payment gateway to change to." +msgstr "" + +#: includes/class-wcs-failed-scheduled-action-manager.php:158 +msgid "Ignore this error" +msgstr "" + +#: includes/class-wcs-failed-scheduled-action-manager.php:163 +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:112 +msgid "Learn more" +msgstr "" + +#: includes/class-wcs-limiter.php:46 +msgid "Limit subscription" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/class-wcs-limiter.php:48 +msgid "Only allow a customer to have one subscription to this product. %1$sLearn more%2$s." +msgstr "" + +#: includes/class-wcs-limiter.php:50 +msgid "Do not limit" +msgstr "" + +#: includes/class-wcs-limiter.php:51 +msgid "Limit to one active subscription" +msgstr "" + +#: includes/class-wcs-limiter.php:52 +msgid "Limit to one of any status" +msgstr "" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:153 +msgid "Auto Renewal Toggle" +msgstr "" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:154 +msgid "Display the auto renewal toggle" +msgstr "" + +#: includes/class-wcs-my-account-auto-renew-toggle.php:155 +msgid "Allow customers to turn on and off automatic renewals from their View Subscription page." +msgstr "" + +#: includes/class-wcs-my-account-payment-methods.php:110 +msgid "The deleted payment method was used for automatic subscription payments, we couldn't find an alternative token payment method token to change your subscriptions to." +msgstr "" + +#. translators: 1: deleted token, 2: new token. +#: includes/class-wcs-my-account-payment-methods.php:128 +msgctxt "used in subscription note" +msgid "Payment method meta updated after customer deleted a token from their My Account page. Payment meta changed from %1$s to %2$s" +msgstr "" + +#. translators: $1: the token/credit card label, 2$-3$: opening and closing strong and link tags +#: includes/class-wcs-my-account-payment-methods.php:133 +msgid "The deleted payment method was used for automatic subscription payments. To avoid failed renewal payments in future the subscriptions using this payment method have been updated to use your %1$s. To change the payment method of individual subscriptions go to your %2$sMy Account > Subscriptions%3$s page." +msgstr "" + +#. translators: 1: token display name, 2: opening link tag, 4: closing link tag, 3: opening link tag. +#: includes/class-wcs-my-account-payment-methods.php:188 +msgid "Would you like to update your subscriptions to use this new payment method - %1$s?%2$sYes%4$s | %3$sNo%4$s" +msgstr "" + +#. translators: 1: previous token, 2: new token. +#: includes/class-wcs-my-account-payment-methods.php:229 +msgctxt "used in subscription note" +msgid "Payment method meta updated after customer changed their default token and opted to update their subscriptions. Payment meta changed from %1$s to %2$s" +msgstr "" + +#. translators: 1$-2$: opening and closing tags. +#: includes/class-wcs-permalink-manager.php:91 +msgid "Error saving Subscriptions endpoints: %1$sSubscriptions%2$s, %1$sView subscription%2$s and %1$sSubscription payment method%2$s cannot be the same. The changes have been reverted." +msgstr "" + +#. translators: %s: invalid type of update argument. +#: includes/class-wcs-post-meta-cache-manager.php:199 +msgid "Invalid update type: %s. Post update types supported are \"add\" or \"delete\". Updates are done on post meta directly." +msgstr "" + +#. translators: placeholder is a page number. +#: includes/class-wcs-query.php:106 +msgid "Subscriptions (page %d)" +msgstr "" + +#: includes/class-wcs-query.php:131 +msgid "My Subscription" +msgstr "" + +#: includes/class-wcs-query.php:288 +msgid "Endpoint for the My Account → Subscriptions page" +msgstr "" + +#: includes/class-wcs-query.php:296 +msgid "View subscription" +msgstr "" + +#: includes/class-wcs-query.php:297 +msgid "Endpoint for the My Account → View Subscription page" +msgstr "" + +#: includes/class-wcs-query.php:305 +msgid "Subscription payment method" +msgstr "" + +#: includes/class-wcs-query.php:306 +msgid "Endpoint for the My Account → Change Subscription Payment Method page" +msgstr "" + +#. translators: %d: subscription ID. +#: includes/class-wcs-remove-item.php:79 +msgctxt "hash before subscription ID" +msgid "Subscription #%d does not exist." +msgstr "" + +#. translators: 1$: product name, 2$: product id +#: includes/class-wcs-remove-item.php:114 +msgctxt "used in order note" +msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" + +#: includes/class-wcs-remove-item.php:119 +msgid "Your request to undo your previous action was unsuccessful." +msgstr "" + +#. translators: 1$: product name, 2$: product id +#: includes/class-wcs-remove-item.php:137 +msgctxt "used in order note" +msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." +msgstr "" + +#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags +#: includes/class-wcs-remove-item.php:140 +msgid "You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" +msgstr "" + +#: includes/class-wcs-remove-item.php:176 +#: includes/class-wcs-user-change-status-handler.php:107 +msgid "Security error. Please contact us if you need assistance." +msgstr "" + +#: includes/class-wcs-remove-item.php:180 +msgid "You cannot modify a subscription that does not belong to you." +msgstr "" + +#: includes/class-wcs-remove-item.php:184 +msgid "You cannot remove an item that does not exist. " +msgstr "" + +#: includes/class-wcs-remove-item.php:188 +msgid "The item was not removed because this Subscription's payment method does not support removing an item." +msgstr "" + +#: includes/class-wcs-retry-manager.php:120 +msgctxt "table heading" +msgid "Renewal Payment Retry" +msgstr "" + +#: includes/class-wcs-retry-manager.php:230 +msgctxt "used in order note as reason for why status changed" +msgid "Retry rule applied:" +msgstr "" + +#: includes/class-wcs-retry-manager.php:268 +msgctxt "used in order note as reason for why status changed" +msgid "Retry rule reapplied:" +msgstr "" + +#: includes/class-wcs-retry-manager.php:324 +msgctxt "used in order note as reason for why order status changed" +msgid "Subscription renewal payment retry:" +msgstr "" + +#: includes/class-wcs-retry-manager.php:328 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Subscription renewal payment retry:" +msgstr "" + +#: includes/class-wcs-retry-manager.php:344 +msgid "Payment retry attempted on renewal order with multiple related subscriptions with no payment method in common." +msgstr "" + +#. translators: 1-2: opening/closing
    tags - linked to staging site, 3: link to live site. +#: includes/class-wcs-staging.php:40 +msgid "Payment processing skipped - renewal order created on %1$sstaging site%2$s under staging site lock. Live site is at %3$s" +msgstr "" + +#: includes/class-wcs-staging.php:83 +msgid "Subscription locked to Manual Renewal while the store is in staging mode. Payment method changes will take effect in live mode." +msgstr "" + +#. translators: placeholder is a payment method title. +#: includes/class-wcs-staging.php:97 +msgid "Subscription locked to Manual Renewal while the store is in staging mode. Live payment method: %s" +msgstr "" + +#. translators: placeholder is a switch type. +#: includes/class-wcs-switch-cart-item.php:309 +msgid "Invalid switch type \"%s\". Switch must be one of: \"upgrade\", \"downgrade\" or \"crossgrade\"." +msgstr "" + +#: includes/class-wcs-switch-totals-calculator.php:196 +msgid "Your cart contained an invalid subscription switch request. It has been removed from your cart." +msgstr "" + +#: includes/class-wcs-template-loader.php:35 +msgid "My Account" +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:57 +msgctxt "order note left on subscription after user action" +msgid "Subscription reactivated by the subscriber from their account page." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:58 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been reactivated." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:61 +msgid "You can not reactivate that subscription until paying to renew it. Please contact us if you need assistance." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:67 +msgctxt "order note left on subscription after user action" +msgid "Subscription put on hold by the subscriber from their account page." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:68 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been put on hold." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:71 +msgid "You can not suspend that subscription - the suspension limit has been reached. Please contact us if you need assistance." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:76 +msgctxt "order note left on subscription after user action" +msgid "Subscription cancelled by the subscriber from their account page." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:77 +msgctxt "Notice displayed to user confirming their action." +msgid "Your subscription has been cancelled." +msgstr "" + +#: includes/class-wcs-user-change-status-handler.php:103 +msgid "That subscription does not exist. Please contact us if you need assistance." +msgstr "" + +#. translators: placeholder is subscription's new status, translated +#: includes/class-wcs-user-change-status-handler.php:116 +msgid "That subscription can not be changed to %s. Please contact us if you need assistance." +msgstr "" + +#: includes/class-wcs-webhooks.php:110 +msgid " Subscription created" +msgstr "" + +#: includes/class-wcs-webhooks.php:111 +msgid " Subscription updated" +msgstr "" + +#: includes/class-wcs-webhooks.php:112 +msgid " Subscription deleted" +msgstr "" + +#: includes/class-wcs-webhooks.php:113 +msgid " Subscription switched" +msgstr "" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:56 +msgid "Generate Customer Subscription Cache" +msgstr "" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:56 +msgid "This will generate the persistent cache for linking users with subscriptions. The caches will be generated overtime in the background (via Action Scheduler)." +msgstr "" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:57 +msgid "Delete Customer Subscription Cache" +msgstr "" + +#: includes/data-stores/class-wcs-customer-store-cached-cpt.php:57 +msgid "This will clear the persistent cache of all of subscriptions stored against users in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as queries to find a given user's subscriptions are run." +msgstr "" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "Generate Related Order Cache" +msgstr "" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:69 +msgid "This will generate the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. The caches will be generated overtime in the background (via Action Scheduler)." +msgstr "" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "Delete Related Order Cache" +msgstr "" + +#: includes/data-stores/class-wcs-related-order-store-cached-cpt.php:70 +msgid "This will clear the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as related order queries are run." +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:72 +msgid "Renew now" +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:100 +msgid "You can not renew this subscription early. Please contact us if you need assistance." +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:106 +msgid "Complete checkout to renew now." +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:151 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:199 +msgctxt "used in order note as reason for why subscription status changed" +msgid "Customer requested to renew early:" +msgstr "" + +#. translators: %s: order ID (linked to details page). +#: includes/early-renewal/class-wcs-cart-early-renewal.php:313 +msgid "Order %s created to record early renewal." +msgstr "" + +#: includes/early-renewal/class-wcs-cart-early-renewal.php:368 +msgid "Cancel" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:53 +msgid "Early Renewal" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:54 +msgid "Accept Early Renewal Payments" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:55 +msgid "With early renewals enabled, customers can renew their subscriptions before the next payment date." +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-manager.php:63 +msgid "Accept Early Renewal Payments via a Modal" +msgstr "" + +#. translators: 1-2: opening/closing tags , 2-3: opening/closing tags for a link to docs on early renewal. +#: includes/early-renewal/class-wcs-early-renewal-manager.php:66 +msgid "Allow customers to bypass the checkout and renew their subscription early from their %1$sMy Account > View Subscription%2$s page. %3$sLearn more.%4$s" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:39 +msgid "Pay now" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:56 +msgid "Renew early" +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:113 +msgid "We were unable to locate that subscription, please try again." +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:118 +msgid "You can't renew the subscription at this time. Please try again." +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:128 +msgid "We couldn't create a renewal order for your subscription, please try again." +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:145 +msgid "Payment for the renewal order was unsuccessful with your payment method on file, please try again." +msgstr "" + +#: includes/early-renewal/class-wcs-early-renewal-modal-handler.php:153 +msgid "Your early renewal order was successful." +msgstr "" + +#. translators: placeholder contains a link to the order's edit screen. +#: includes/early-renewal/wcs-early-renewal-functions.php:169 +msgid "Customer successfully renewed early with order %s." +msgstr "" + +#. translators: placeholder contains a link to the order's edit screen. +#: includes/early-renewal/wcs-early-renewal-functions.php:172 +msgid "Failed to update subscription dates after customer renewed early with order %s." +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:26 +msgid "Cancelled Subscription" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:27 +msgid "Cancelled Subscription emails are sent when a customer's subscription is cancelled (either by a store manager, or the customer)." +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:29 +msgid "Subscription Cancelled" +msgstr "" + +#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out +#: includes/emails/class-wcs-email-cancelled-subscription.php:31 +msgctxt "default email subject for cancelled emails sent to the admin" +msgid "[%s] Subscription Cancelled" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:143 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:210 +#: includes/emails/class-wcs-email-expired-subscription.php:141 +#: includes/emails/class-wcs-email-on-hold-subscription.php:141 +msgctxt "an email notification" +msgid "Enable/Disable" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:145 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:212 +#: includes/emails/class-wcs-email-expired-subscription.php:143 +#: includes/emails/class-wcs-email-on-hold-subscription.php:143 +msgid "Enable this email notification" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:149 +#: includes/emails/class-wcs-email-expired-subscription.php:147 +#: includes/emails/class-wcs-email-on-hold-subscription.php:147 +msgctxt "of an email" +msgid "Recipient(s)" +msgstr "" + +#. translators: placeholder is admin email +#: includes/emails/class-wcs-email-cancelled-subscription.php:152 +#: includes/emails/class-wcs-email-expired-subscription.php:150 +#: includes/emails/class-wcs-email-on-hold-subscription.php:150 +msgid "Enter recipients (comma separated) for this email. Defaults to %s." +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:157 +#: includes/emails/class-wcs-email-expired-subscription.php:155 +#: includes/emails/class-wcs-email-on-hold-subscription.php:155 +msgctxt "of an email" +msgid "Subject" +msgstr "" + +#. translators: %s: default e-mail subject. +#: includes/emails/class-wcs-email-cancelled-subscription.php:160 +#: includes/emails/class-wcs-email-expired-subscription.php:158 +#: includes/emails/class-wcs-email-on-hold-subscription.php:158 +msgid "This controls the email subject line. Leave blank to use the default subject: %s." +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:165 +#: includes/emails/class-wcs-email-expired-subscription.php:163 +#: includes/emails/class-wcs-email-on-hold-subscription.php:163 +msgctxt "Name the setting that controls the main heading contained within the email notification" +msgid "Email Heading" +msgstr "" + +#. translators: %s: default e-mail heading. +#: includes/emails/class-wcs-email-cancelled-subscription.php:168 +msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:173 +#: includes/emails/class-wcs-email-expired-subscription.php:171 +#: includes/emails/class-wcs-email-on-hold-subscription.php:171 +msgctxt "text, html or multipart" +msgid "Email type" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:175 +#: includes/emails/class-wcs-email-expired-subscription.php:173 +#: includes/emails/class-wcs-email-on-hold-subscription.php:173 +msgid "Choose which format of email to send." +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:179 +#: includes/emails/class-wcs-email-expired-subscription.php:177 +#: includes/emails/class-wcs-email-on-hold-subscription.php:177 +msgctxt "email type" +msgid "Plain text" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:180 +#: includes/emails/class-wcs-email-expired-subscription.php:178 +#: includes/emails/class-wcs-email-on-hold-subscription.php:178 +msgctxt "email type" +msgid "HTML" +msgstr "" + +#: includes/emails/class-wcs-email-cancelled-subscription.php:181 +#: includes/emails/class-wcs-email-expired-subscription.php:179 +#: includes/emails/class-wcs-email-on-hold-subscription.php:179 +msgctxt "email type" +msgid "Multipart" +msgstr "" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:25 +msgid "Completed Renewal Order" +msgstr "" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:26 +msgid "Renewal order complete emails are sent to the customer when a subscription renewal order is marked complete and usually indicates that the item for that renewal period has been shipped." +msgstr "" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:29 +msgctxt "Default email heading for email to customer on completed renewal order" +msgid "Your renewal order is complete" +msgstr "" + +#. translators: $1: {blogname}, $2: {order_date}, variables that will be substituted when email is sent out +#: includes/emails/class-wcs-email-completed-renewal-order.php:31 +msgctxt "Default email subject for email to customer on completed renewal order" +msgid "Your %1$s renewal order from %2$s is complete" +msgstr "" + +#: includes/emails/class-wcs-email-completed-renewal-order.php:38 +msgctxt "Default email heading for email with downloadable files in it" +msgid "Your subscription renewal order is complete - download your files" +msgstr "" + +#. translators: $1: {blogname}, $2: {order_date}, variables will be substituted when email is sent out +#: includes/emails/class-wcs-email-completed-renewal-order.php:40 +msgctxt "Default email subject for email with downloadable files in it" +msgid "Your %1$s subscription renewal order from %2$s is complete - download your files" +msgstr "" + +#: includes/emails/class-wcs-email-completed-switch-order.php:26 +msgid "Subscription Switch Complete" +msgstr "" + +#: includes/emails/class-wcs-email-completed-switch-order.php:27 +msgid "Subscription switch complete emails are sent to the customer when a subscription is switched successfully." +msgstr "" + +#: includes/emails/class-wcs-email-completed-switch-order.php:30 +msgid "Your subscription change is complete" +msgstr "" + +#: includes/emails/class-wcs-email-completed-switch-order.php:31 +msgid "Your {blogname} subscription change from {order_date} is complete" +msgstr "" + +#: includes/emails/class-wcs-email-completed-switch-order.php:38 +msgid "Your subscription change is complete - download your files" +msgstr "" + +#: includes/emails/class-wcs-email-completed-switch-order.php:39 +msgid "Your {blogname} subscription change from {order_date} is complete - download your files" +msgstr "" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:23 +msgid "On-hold Renewal Order" +msgstr "" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:24 +msgid "This is an order notification sent to customers containing order details after a renewal order is placed on-hold." +msgstr "" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:25 +msgid "Your {blogname} renewal order has been received!" +msgstr "" + +#: includes/emails/class-wcs-email-customer-on-hold-renewal-order.php:26 +msgid "Thank you for your renewal order" +msgstr "" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:24 +msgid "Customer Payment Retry" +msgstr "" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:25 +msgid "Sent to a customer when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future. The email contains the renewal order information, date of the scheduled retry and payment links to allow the customer to pay for the renewal order manually instead of waiting for the automatic retry." +msgstr "" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:32 +msgid "Automatic payment failed for {order_number}, we will retry {retry_time}" +msgstr "" + +#: includes/emails/class-wcs-email-customer-payment-retry.php:33 +msgid "Automatic payment failed for order {order_number}" +msgstr "" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:40 +msgid "Customer Renewal Invoice" +msgstr "" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:41 +msgid "Sent to a customer when the subscription is due for renewal and the renewal requires a manual payment, either because it uses manual renewals or the automatic recurring payment failed for the initial attempt and all automatic retries (if any). The email contains renewal order information and payment links." +msgstr "" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:48 +msgid "Invoice for renewal order {order_number} from {order_date}" +msgstr "" + +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:49 +msgid "Invoice for renewal order {order_number}" +msgstr "" + +#: includes/emails/class-wcs-email-expired-subscription.php:26 +msgid "Expired Subscription" +msgstr "" + +#: includes/emails/class-wcs-email-expired-subscription.php:27 +msgid "Expired Subscription emails are sent when a customer's subscription expires." +msgstr "" + +#: includes/emails/class-wcs-email-expired-subscription.php:29 +msgid "Subscription Expired" +msgstr "" + +#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out +#: includes/emails/class-wcs-email-expired-subscription.php:31 +msgctxt "default email subject for expired emails sent to the admin" +msgid "[%s] Subscription Expired" +msgstr "" + +#: includes/emails/class-wcs-email-expired-subscription.php:78 +#: includes/emails/class-wcs-email-on-hold-subscription.php:78 +msgid "Subscription argument passed in is not an object." +msgstr "" + +#. translators: %s: default e-mail heading. +#: includes/emails/class-wcs-email-expired-subscription.php:166 +#: includes/emails/class-wcs-email-on-hold-subscription.php:166 +msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." +msgstr "" + +#: includes/emails/class-wcs-email-new-renewal-order.php:22 +msgid "New Renewal Order" +msgstr "" + +#: includes/emails/class-wcs-email-new-renewal-order.php:23 +msgid "New renewal order emails are sent when a subscription renewal payment is processed." +msgstr "" + +#: includes/emails/class-wcs-email-new-renewal-order.php:25 +msgid "New subscription renewal order" +msgstr "" + +#: includes/emails/class-wcs-email-new-renewal-order.php:26 +msgid "[{blogname}] New subscription renewal order ({order_number}) - {order_date}" +msgstr "" + +#: includes/emails/class-wcs-email-new-switch-order.php:22 +#: includes/emails/class-wcs-email-new-switch-order.php:25 +msgid "Subscription Switched" +msgstr "" + +#: includes/emails/class-wcs-email-new-switch-order.php:23 +msgid "Subscription switched emails are sent when a customer switches a subscription." +msgstr "" + +#: includes/emails/class-wcs-email-new-switch-order.php:26 +msgid "[{blogname}] Subscription Switched ({order_number}) - {order_date}" +msgstr "" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:26 +msgid "Suspended Subscription" +msgstr "" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:27 +msgid "Suspended Subscription emails are sent when a customer manually suspends their subscription." +msgstr "" + +#: includes/emails/class-wcs-email-on-hold-subscription.php:29 +msgid "Subscription Suspended" +msgstr "" + +#. translators: placeholder is {blogname}, a variable that will be substituted when email is sent out +#: includes/emails/class-wcs-email-on-hold-subscription.php:31 +msgctxt "default email subject for suspended emails sent to the admin" +msgid "[%s] Subscription Suspended" +msgstr "" + +#: includes/emails/class-wcs-email-payment-retry.php:26 +msgid "Payment Retry" +msgstr "" + +#: includes/emails/class-wcs-email-payment-retry.php:27 +msgid "Payment retry emails are sent to chosen recipient(s) when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future." +msgstr "" + +#: includes/emails/class-wcs-email-payment-retry.php:29 +msgid "Automatic renewal payment failed" +msgstr "" + +#: includes/emails/class-wcs-email-payment-retry.php:30 +msgid "[{site_title}] Automatic payment failed for {order_number}, retry scheduled to run {retry_time}" +msgstr "" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:24 +msgid "Processing Renewal order" +msgstr "" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:25 +msgid "This is an order notification sent to the customer after payment for a subscription renewal order is completed. It contains the renewal order details." +msgstr "" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:28 +msgid "Thank you for your order" +msgstr "" + +#: includes/emails/class-wcs-email-processing-renewal-order.php:29 +msgid "Your {blogname} renewal order receipt from {order_date}" +msgstr "" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:166 +msgid "Sorry, it seems there are no available payment methods which support subscriptions. Please see %1$sEnabling Payment Gateways for Subscriptions%2$s if you require assistance." +msgstr "" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:168 +msgid "Sorry, it seems there are no available payment methods which support subscriptions. Please contact us if you require assistance or wish to make alternate arrangements." +msgstr "" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:303 +msgid "Supported features:" +msgstr "" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:306 +msgid "Subscription features:" +msgstr "" + +#: includes/gateways/class-wc-subscriptions-payment-gateways.php:310 +msgid "Change payment features:" +msgstr "" + +#: includes/gateways/paypal/class-wcs-paypal.php:220 +msgid "Unable to find order for PayPal billing agreement." +msgstr "" + +#: includes/gateways/paypal/class-wcs-paypal.php:282 +msgid "An error occurred, please try again or try an alternate form of payment." +msgstr "" + +#: includes/gateways/paypal/class-wcs-paypal.php:362 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:320 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:336 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:384 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:150 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:156 +msgctxt "hash before the order number. Used as a character to remove from the actual order number" +msgid "#" +msgstr "" + +#. translators: placeholders are PayPal API error code and PayPal API error message +#: includes/gateways/paypal/class-wcs-paypal.php:386 +msgid "PayPal API error: (%1$d) %2$s" +msgstr "" + +#. translators: placeholder is PayPal transaction status message +#: includes/gateways/paypal/class-wcs-paypal.php:391 +msgid "PayPal Transaction Held: %s" +msgstr "" + +#. translators: placeholder is PayPal transaction status message +#: includes/gateways/paypal/class-wcs-paypal.php:403 +msgid "PayPal payment declined: %s" +msgstr "" + +#. translators: placeholder is a transaction ID. +#: includes/gateways/paypal/class-wcs-paypal.php:407 +msgid "PayPal payment approved (ID: %s)" +msgstr "" + +#: includes/gateways/paypal/class-wcs-paypal.php:460 +msgid "" +"Are you sure you want to change the payment method from PayPal standard?\n" +"\n" +"This will suspend the subscription at PayPal." +msgstr "" + +#: includes/gateways/paypal/class-wcs-paypal.php:626 +msgctxt "used in User Agent data sent to PayPal to help identify where a payment came from" +msgid "WooCommerce Subscriptions PayPal" +msgstr "" + +#. translators: $1 and $2 are opening and closing strong tags, respectively. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:63 +msgid "It is %1$sstrongly recommended you do not change the Receiver Email address%2$s if you have active subscriptions with PayPal. Doing so can break existing subscriptions." +msgstr "" + +#. translators: placeholders are opening and closing link tags. 1$-2$: to docs on woocommerce, 3$-4$ to gateway settings on the site +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:110 +msgid "PayPal is inactive for subscription transactions. Please %1$sset up the PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for Subscriptions." +msgstr "" + +#. translators: opening/closing tags - links to documentation. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122 +msgid "%1$sPayPal Reference Transactions are not enabled on your account%2$s, some subscription management features are not enabled. Please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" + +#. translators: opening/closing tags - links to documentation. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:126 +msgid "%1$sPayPal Reference Transactions are not enabled on your account%2$s. If you wish to use PayPal Reference Transactions with Subscriptions, please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s" +msgstr "" + +#. translators: placeholders are opening and closing strong tags. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:148 +msgid "%1$sPayPal Reference Transactions are enabled on your account%2$s. All subscription management features are now enabled. Happy selling!" +msgstr "" + +#. translators: placeholders are link opening and closing tags. 1$-2$: to gateway settings, 3$-4$: support docs on woocommerce.com +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:159 +msgid "There is a problem with PayPal. Your API credentials may be incorrect. Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s." +msgstr "" + +#. translators: placeholders are opening and closing link tags. 1$-2$: docs on woocommerce, 3$-4$: dismiss link +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:172 +msgid "There is a problem with PayPal. Your PayPal account is issuing out-of-date subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." +msgstr "" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:194 +msgid "Ignore this error (not recommended)" +msgstr "" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:199 +msgid "Open a ticket" +msgstr "" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:286 +msgid "PayPal Subscription ID:" +msgstr "" + +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:312 +msgid "Enable PayPal Standard for Subscriptions" +msgstr "" + +#. translators: Placeholders are the opening and closing link tags. +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:320 +msgid "Before enabling PayPal Standard for Subscriptions, please note, when using PayPal Standard, customers are locked into using PayPal Standard for the life of their subscription, and PayPal Standard has a number of limitations. Please read the guide on %1$swhy we don't recommend PayPal Standard%2$s for Subscriptions before choosing to enable this option." +msgstr "" + +#. translators: placeholder is blogname +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:71 +msgctxt "data sent to paypal" +msgid "Orders with %s" +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:279 +msgid "Total Discount" +msgstr "" + +#. translators: placeholder is blogname +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:306 +msgid "%s - Order" +msgstr "" + +#. translators: 1$: new status (e.g. "Cancel"), 2$: blog name +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:416 +msgctxt "data sent to paypal" +msgid "%1$s subscription event triggered at %2$s" +msgstr "" + +#. translators: %s: product SKU. +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:536 +msgid "SKU: %s" +msgstr "" + +#. translators: placeholder is localised datetime +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119 +msgid "expected clearing date %s" +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:136 +msgctxt "used in api error message if there is no severity code from PayPal" +msgid "Error" +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:138 +msgctxt "used in api error message if there is no long message" +msgid "Unknown error" +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:150 +#: templates/admin/deprecated/order-shipping-html.php:14 +#: templates/admin/deprecated/order-tax-html.php:9 +msgctxt "no information about something" +msgid "N/A" +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php:94 +msgid "Billing agreement cancelled at PayPal." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:275 +msgctxt "when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method" +msgid "IPN subscription payment method changed to PayPal." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:279 +msgid "IPN subscription sign up completed." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:332 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:417 +msgid "IPN subscription payment completed." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:379 +msgid "IPN subscription failing payment method changed." +msgstr "" + +#. translators: placeholder is payment status (e.g. "completed") +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:427 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:436 +msgctxt "used in order note" +msgid "IPN subscription payment %s." +msgstr "" + +#. translators: 1: payment status (e.g. "completed"), 2: pending reason. +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:440 +msgctxt "used in order note" +msgid "IPN subscription payment %1$s for reason: %2$s." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:469 +msgid "IPN subscription suspended." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:492 +msgid "IPN subscription cancelled." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:508 +msgid "IPN subscription payment failure." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:646 +msgid "Invalid PayPal IPN Payload: unable to find matching subscription." +msgstr "" + +#. translators: 1$: subscription ID, 2$: names of items, comma separated +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:75 +msgctxt "item name sent to paypal" +msgid "Subscription %1$s - %2$s" +msgstr "" + +#. translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma separated +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:78 +msgctxt "item name sent to paypal" +msgid "Subscription %1$s (Order %2$s) - %3$s" +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php:266 +msgid "Subscription changed from PayPal Standard to PayPal Reference Transactions via customer initiated switch. The PayPal Standard subscription has been suspended." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42 +msgid "Subscription cancelled with PayPal." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:53 +msgid "Subscription suspended with PayPal." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:66 +msgid "Subscription reactivated with PayPal." +msgstr "" + +#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:113 +msgid "PayPal API error - credentials are incorrect." +msgstr "" + +#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:18 +msgid "A fatal error has occurred while processing a recent subscription payment with PayPal. Please %1$sopen a new ticket at WooCommerce Support%3$s immediately to get this resolved. %2$sLearn more »%3$s" +msgstr "" + +#. translators: $1 and $2 are opening link tags, $3 is a closing link tag. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:29 +msgid "To resolve this as quickly as possible, please create a %1$stemporary administrator account%3$s with the user email woologin@woocommerce.com and share the credentials with us via %2$sQuickForget.com%3$s." +msgstr "" + +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:36 +msgid "Last recorded error:" +msgstr "" + +#. translators: $1 is the log file name. $2 and $3 are opening and closing link tags, respectively. +#: includes/gateways/paypal/includes/templates/html-ipn-failure-notice.php:46 +msgid "To see the full error, view the %1$s log file from the %2$sWooCommerce logs screen.%3$s." +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:46 +msgid "Automatic Failed Payment Retries" +msgstr "" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:100 +msgid "%d Pending Payment Retry" +msgid_plural "%d Pending Payment Retries" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:104 +msgid "%d Processing Payment Retry" +msgid_plural "%d Processing Payment Retries" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:108 +msgid "%d Failed Payment Retry" +msgid_plural "%d Failed Payment Retries" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:112 +msgid "%d Successful Payment Retry" +msgid_plural "%d Successful Payment Retries" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d: retry count. +#: includes/payment-retry/class-wcs-retry-admin.php:116 +msgid "%d Cancelled Payment Retry" +msgid_plural "%d Cancelled Payment Retries" +msgstr[0] "" +msgstr[1] "" + +#: includes/payment-retry/class-wcs-retry-admin.php:144 +msgid "Retry Failed Payments" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:145 +msgid "Enable automatic retry of failed recurring payments" +msgstr "" + +#. translators: 1,2: opening/closing link tags (to documentation). +#: includes/payment-retry/class-wcs-retry-admin.php:150 +msgid "Attempt to recover recurring revenue that would otherwise be lost due to payment methods being declined only temporarily. %1$sLearn more%2$s." +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:172 +msgctxt "label for the system status page" +msgid "Custom Retry Rules" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:180 +msgctxt "label for the system status page" +msgid "Custom Retry Rule Class" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:188 +msgctxt "label for the system status page" +msgid "Custom Raw Retry Rule" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:196 +msgctxt "label for the system status page" +msgid "Custom Retry Rule" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-admin.php:204 +msgctxt "label for the system status page" +msgid "Retries Migration Status" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:25 +msgid "Payment retry posts store details about the automatic retry of failed renewal payments." +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:35 +msgctxt "Post type name" +msgid "Renewal Payment Retries" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:36 +msgid "Renewal Payment Retry" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:37 +msgctxt "Admin menu name" +msgid "Renewal Payment Retries" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:38 +msgid "Add" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:39 +msgid "Add New Retry" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:41 +msgid "Edit Retry" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:42 +msgid "New Retry" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:43 +#: includes/payment-retry/class-wcs-retry-post-store.php:44 +msgid "View Retry" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:45 +msgid "Search Renewal Payment Retries" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:46 +msgid "No retries found" +msgstr "" + +#: includes/payment-retry/class-wcs-retry-post-store.php:47 +msgid "No retries found in trash" +msgstr "" + +#. Translators: %s subscription number. +#: includes/privacy/class-wcs-privacy-erasers.php:71 +msgid "Removed personal data from subscription %s." +msgstr "" + +#. Translators: %s subscription number. +#: includes/privacy/class-wcs-privacy-erasers.php:75 +msgid "Personal data within subscription %s has been retained." +msgstr "" + +#: includes/privacy/class-wcs-privacy-erasers.php:189 +msgid "Personal data removed." +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:77 +msgid "Subscription Number" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:78 +msgid "Created Date" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:79 +msgid "Recurring Total" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:80 +msgid "Subscription Items" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:81 +msgid "IP Address" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:82 +msgid "Browser User Agent" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:83 +#: wcs-functions.php:284 +msgid "Billing Address" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:84 +#: wcs-functions.php:283 +msgid "Shipping Address" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:85 +msgid "Phone Number" +msgstr "" + +#: includes/privacy/class-wcs-privacy-exporters.php:86 +msgid "Email Address" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:43 +#: includes/privacy/class-wcs-privacy.php:44 +msgid "Subscriptions Data" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:92 +msgid "By using WooCommerce Subscriptions, you may be storing personal data and depending on which third-party payment processors you’re using to take subscription payments, you may be sharing personal data with external sources." +msgstr "" + +#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:94 +msgid "What we collect and store" +msgstr "" + +#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:95 +msgid "For the purposes of processing recurring subscription payments, we store the customer's name, billing address, shipping address, email address, phone number and credit card/payment details." +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:96 +msgid "What we share with others" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:97 +msgid "What personal information your store shares with external sources depends on which third-party payment processor plugins you are using to collect subscription payments. We recommend that you consult with their privacy policies to inform this section of your privacy policy." +msgstr "" + +#. translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation. +#: includes/privacy/class-wcs-privacy.php:99 +msgid "If you are using PayPal Standard or PayPal Reference transactions please see the %1$sPayPal Privacy Policy%2$s for more details." +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:109 +msgid "Cancel and remove personal data" +msgstr "" + +#. translators: %d: number of subscriptions affected. +#: includes/privacy/class-wcs-privacy.php:176 +msgid "Removed personal data from %d subscription." +msgid_plural "Removed personal data from %d subscriptions." +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholders are opening and closing tags. +#: includes/privacy/class-wcs-privacy.php:195 +msgid "%1$sNote:%2$s Orders which are related to subscriptions will not be included in the orders affected by these settings." +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:215 +msgid "account erasure request" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:221 +msgid "Remove personal data from subscriptions" +msgstr "" + +#. Translators: %s URL to erasure request screen. +#: includes/privacy/class-wcs-privacy.php:223 +msgid "When handling an %s, should personal data within subscriptions be retained or removed?" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:232 +msgid "Retain ended subscriptions" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:233 +msgid "Retain ended subscriptions and their related orders for a specified duration before anonymizing the personal data within them." +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:236 +msgid "N/A" +msgstr "" + +#: includes/privacy/class-wcs-privacy.php:277 +msgid "Customers with a subscription are excluded from this setting." +msgstr "" + +#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 & 1.5") +#: includes/upgrades/class-wc-subscriptions-upgrader.php:356 +msgid "Database updated to version %s" +msgstr "" + +#. translators: placeholder is number of upgraded subscriptions +#: includes/upgrades/class-wc-subscriptions-upgrader.php:364 +msgctxt "used in the subscriptions upgrader" +msgid "Marked %s subscription products as \"sold individually\"." +msgstr "" + +#. translators: 1$: number of action scheduler hooks upgraded, 2$: "{execution_time}", will be replaced on front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:373 +msgid "Migrated %1$s subscription related hooks to the new scheduler (in %2$s seconds)." +msgstr "" + +#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}", will be replaced on front end with actual time it took +#: includes/upgrades/class-wc-subscriptions-upgrader.php:385 +msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)." +msgstr "" + +#. translators: placeholder is "{time_left}", will be replaced on front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:388 +#: includes/upgrades/class-wc-subscriptions-upgrader.php:434 +msgctxt "Message that gets sent to front end." +msgid "Estimated time left (minutes:seconds): %s" +msgstr "" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, 4$: break tag +#: includes/upgrades/class-wc-subscriptions-upgrader.php:398 +msgid "Unable to upgrade subscriptions.%4$sError: %1$s%4$sPlease refresh the page and try again. If problem persists, %2$scontact support%3$s." +msgstr "" + +#. translators: placeholder is the number of subscriptions repaired +#: includes/upgrades/class-wc-subscriptions-upgrader.php:413 +msgctxt "Repair message that gets sent to front end." +msgid "Repaired %d subscriptions with incorrect dates, line tax data or missing customer notes." +msgstr "" + +#. translators: placeholder is number of subscriptions that were checked and did not need repairs. There's a space at the beginning! +#: includes/upgrades/class-wc-subscriptions-upgrader.php:419 +msgctxt "Repair message that gets sent to front end." +msgid " %d other subscription was checked and did not need any repairs." +msgid_plural "%d other subscriptions were checked and did not need any repairs." +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is "{execution_time}", which will be replaced on front end with actual time +#: includes/upgrades/class-wc-subscriptions-upgrader.php:423 +msgctxt "Repair message that gets sent to front end." +msgid "(in %s seconds)" +msgstr "" + +#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL languages. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:426 +msgctxt "The assembled repair message that gets sent to front end." +msgid "%1$s%2$s %3$s" +msgstr "" + +#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag, 4$: break tag +#: includes/upgrades/class-wc-subscriptions-upgrader.php:445 +msgctxt "Error message that gets sent to front end when upgrading Subscriptions" +msgid "Unable to repair subscriptions.%4$sError: %1$s%4$sPlease refresh the page and try again. If problem persists, %2$scontact support%3$s." +msgstr "" + +#: includes/upgrades/class-wc-subscriptions-upgrader.php:649 +msgid "Welcome to WooCommerce Subscriptions 2.1" +msgstr "" + +#: includes/upgrades/class-wc-subscriptions-upgrader.php:649 +msgid "About WooCommerce Subscriptions" +msgstr "" + +#. translators: 1-2: opening/closing tags, 3: active version of Subscriptions, 4: current version of Subscriptions, 5-6: opening/closing tags linked to ticket form, 7-8: opening/closing tags linked to documentation. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:831 +msgid "%1$sWarning!%2$s It appears that you have downgraded %1$sWooCommerce Subscriptions%2$s from %3$s to %4$s. Downgrading the plugin in this way may cause issues. Please update to %3$s or higher, or %5$sopen a new support ticket%6$s for further assistance. %7$sLearn more »%8$s" +msgstr "" + +#. translators: 1-2: opening/closing tags, 3-4: opening/closing tags linked to ticket form. +#: includes/upgrades/class-wc-subscriptions-upgrader.php:905 +msgid "%1$sWarning!%2$s We discovered an issue in %1$sWooCommerce Subscriptions 2.3.0 - 2.3.2%2$s that may cause your subscription renewal order and customer subscription caches to contain invalid data. For information about how to update the cached data, please %3$sopen a new support ticket%4$s." +msgstr "" + +#: includes/upgrades/class-wcs-repair-suspended-paypal-subscriptions.php:51 +msgid "Subscription suspended by Database repair script. This subscription was suspended via PayPal." +msgstr "" + +#: includes/upgrades/class-wcs-upgrade-2-2-7.php:60 +msgid "Subscription end date in the past" +msgstr "" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:80 +msgctxt "plugin version number used in admin notice" +msgid "3.1" +msgstr "" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:85 +msgid "v3 REST API endpoint support" +msgstr "" + +#. translators: 1-3: opening/closing tags - link to documentation. +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:88 +msgid "Webhook and REST API users can now use v3 subscription endpoints. Click here to %1$slearn more%2$s about the REST API and check out the technical API docs %3$shere%2$s." +msgstr "" + +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:95 +msgid "WooCommerce checkout and cart blocks integration" +msgstr "" + +#. translators: 1-2: opening/closing tags - link to documentation. +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:98 +msgid "Subscriptions is now compatible with the WooCommerce cart and checkout blocks. You can learn more about the compatibility status of the cart & checkout blocks %1$shere%2$s." +msgstr "" + +#. translators: placeholder is Subscription version string ('3.1') +#: includes/upgrades/class-wcs-upgrade-notice-manager.php:105 +msgid "Welcome to WooCommerce Subscriptions %s!" +msgstr "" + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/templates/update-welcome-notice.php:2 +#: includes/upgrades/templates/wcs-about-2-0.php:23 +#: includes/upgrades/templates/wcs-about.php:22 +msgid "Thank you for updating to the latest version of WooCommerce Subscriptions." +msgstr "" + +#. translators: placeholder $1 is the Subscription version string ('2.3'), $2-3 are opening and closing tags +#: includes/upgrades/templates/update-welcome-notice.php:5 +msgid "Version %1$s brings some new improvements requested by store managers just like you (and possibly even by %2$syou%3$s)." +msgstr "" + +#: includes/upgrades/templates/update-welcome-notice.php:6 +#: includes/upgrades/templates/wcs-about-2-0.php:25 +#: includes/upgrades/templates/wcs-about.php:24 +msgid "We hope you enjoy it!" +msgstr "" + +#: includes/upgrades/templates/update-welcome-notice.php:8 +msgid "What's new?" +msgstr "" + +#. translators: placeholder is Subscription version string ('2.3') +#: includes/upgrades/templates/update-welcome-notice.php:16 +msgid "Want to know more about Subscriptions %s?" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:20 +msgid "Welcome to Subscriptions 2.0" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:24 +msgid "Version 2.0 has been in development for more than a year. We've reinvented the extension to take into account 3 years of feedback from store managers." +msgstr "" + +#. translators: placeholder is version number +#: includes/upgrades/templates/wcs-about-2-0.php:31 +#: includes/upgrades/templates/wcs-about.php:30 +msgid "Version %s" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:36 +#: woocommerce-subscriptions.php:1202 +msgctxt "short for documents" +msgid "Docs" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:42 +#: includes/upgrades/templates/wcs-about.php:41 +msgid "Check Out What's New" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:51 +msgid "Multiple Subscriptions" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:52 +msgid "It's now easier for your customers to buy more subscriptions!" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:53 +msgid "Customers can now purchase different subscription products in one transaction. The products can bill on any schedule and have any combination of sign-up fees and/or free trials." +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/upgrades/templates/wcs-about-2-0.php:56 +msgid "Learn more about the new %smultiple subscriptions%s feature." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:68 +msgid "New Add/Edit Subscription Screen" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:69 +msgid "Subscriptions v2.0 introduces a new administration interface to add or edit a subscription. You can make all the familiar changes, like modifying recurring totals or subscription status. You can also make some new modifications, like changing the expiration date, adding a shipping cost or adding a product line item." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:72 +msgid "The new interface is also built on the existing %sEdit Order%s screen. If you've ever modified an order, you already know how to modify a subscription." +msgstr "" + +#. translators: placeholers are link tags: 1$-2$ new subscription page, 3$-4$: docs on woocommerce.com +#: includes/upgrades/templates/wcs-about-2-0.php:76 +msgid "%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new interface." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:87 +msgid "New View Subscription Page" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:91 +msgid "Your customers can now view the full details of a subscription, including line items, billing and shipping address, billing schedule and renewal orders, from a special %sMy Account > View Subscription%s page." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:93 +msgid "This new page is also where the customer can suspend or cancel their subscription, change payment method, change shipping address or upgrade/downgrade an item." +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: includes/upgrades/templates/wcs-about-2-0.php:97 +msgid "Learn more about the new %sView Subscription page%s." +msgstr "" + +#. translators: placeholders are for opening and closing link () tags +#: includes/upgrades/templates/wcs-about-2-0.php:111 +msgid "By default, adding new files to an existing subscription product will automatically provide active subscribers with access to the new files. However, now you can enable a %snew content dripping setting%s to provide subscribers with access to new files only after the next renewal payment." +msgstr "" + +#. translators: placeholders are for opening and closing link () tags +#. translators: placeholders are opening and closing anchor tags linking to documentation +#: includes/upgrades/templates/wcs-about-2-0.php:115 +#: includes/upgrades/templates/wcs-about-2-0.php:128 +#: includes/upgrades/templates/wcs-about-2-0.php:141 +#: includes/upgrades/templates/wcs-about.php:120 +#: includes/upgrades/templates/wcs-about.php:131 +#: includes/upgrades/templates/wcs-about.php:142 +#: includes/upgrades/templates/wcs-about.php:170 +#: includes/upgrades/templates/wcs-about.php:191 +msgid "%sLearn more »%s" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:121 +msgctxt "h3 on the About Subscriptions page for this new feature" +msgid "Change Payment Method" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:124 +msgid "For a store manager to change a subscription from automatic to manual renewal payments (or manual to automatic) with Subscriptions v1.5, the database needed to be modified directly. Subscriptions now provides a way for payment gateways to allow you to change that from the new %sEdit Subscription%s interface." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:134 +msgid "Change Trial and End Dates" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:137 +msgid "It was already possible to change a subscription's next payment date, but some store managers wanted to provide a customer with an extended free trial or add an extra month to the expiration date. Now you can change all of these dates from the %sEdit Subscription%s screen." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:150 +msgid "And much more..." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:157 +#: includes/upgrades/templates/wcs-about.php:151 +msgid "Peek Under the Hood for Developers" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:158 +msgid "Subscriptions 2.0 introduces a new architecture built on the WooCommerce Custom Order Types API." +msgstr "" + +#. translators: placeholders are opening and closing code tags +#: includes/upgrades/templates/wcs-about-2-0.php:164 +msgid "New %sshop_subscription%s Post Type" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:166 +msgid "By making a subscription a Custom Order Type, a subscription is also now a custom post type. This makes it faster to query subscriptions and it uses a database schema that is as scalable as WordPress posts and pages." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:169 +msgid "Developers can also now use all the familiar WordPress functions, like %sget_posts()%s, to query or modify subscription data." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about-2-0.php:175 +msgid "New %sWC_Subscription%s Object" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:177 +msgid "Subscriptions 2.0 introduces a new object for working with a subscription at the application level. The cumbersome APIs for retrieving or modifying a subscription's data are gone!" +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: includes/upgrades/templates/wcs-about-2-0.php:180 +msgid "Because the %sWC_Subscription%s class extends %sWC_Order%s, you can use its familiar methods, like %s$subscription->update_status()%s or %s$subscription->get_total()%s." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:184 +msgid "REST API Endpoints" +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:185 +msgid "We didn't just improve interfaces for humans, we also improved them for computers. Your applications can now create, read, update or delete subscriptions via RESTful API endpoints." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: includes/upgrades/templates/wcs-about-2-0.php:188 +msgid "Want to list all the subscriptions on a site? Get %sexample.com/wc-api/v2/subscriptions/%s. Want the details of a specific subscription? Get %s/wc-api/v2/subscriptions//%s." +msgstr "" + +#: includes/upgrades/templates/wcs-about-2-0.php:194 +msgid "Go to WooCommerce Subscriptions Settings" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:19 +msgid "Welcome to Subscriptions 2.1!" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:23 +msgid "Version 2.1 introduces some great new features requested by store managers just like you (and possibly even by %syou%s)." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:35 +msgctxt "short for documents" +msgid "Documentation" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:49 +msgid "Subscription Reports" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:50 +msgid "How many customers stay subscribed for more than 6 months? What is the average lifetime value of your subscribers? How much renewal revenue will your store earn next month?" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:51 +msgid "These are important questions for any subscription commerce business." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:52 +msgid "Prior to Subscriptions 2.1, they were not easy to answer. Subscriptions 2.1 introduces new reports to answer these questions, and many more." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:54 +msgid "View Reports" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:55 +msgctxt "learn more link to subscription reports documentation" +msgid "Learn More" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:67 +msgid "Automatic Failed Payment Retry" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:68 +msgid "Failed recurring payments can now be retried automatically. This helps recover revenue that would otherwise be lost due to payment methods being declined only temporarily." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:69 +msgid "By default, Subscriptions will retry the payment 5 times over 7 days. The rules that control the retry system can be modified to customise:" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:71 +msgid "the total number of retry attempts" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:72 +msgid "how long to wait between retry attempts" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:73 +msgid "emails sent to the customer and store manager" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:74 +msgid "the status applied to the renewal order and subscription" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:76 +msgid "The retry system is disabled by default. To enable it, visit the Subscriptions settings administration screen." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:78 +msgid "Enable Automatic Retry" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:79 +msgctxt "learn more link to failed payment retry documentation" +msgid "Learn More" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:90 +msgid "New Subscription Emails" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:91 +msgid "Subscriptions 2.1 also introduces a number of new emails to notify you when:" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:93 +msgid "a customer suspends a subscription" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:94 +msgid "an automatic payment fails" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:95 +msgid "a subscription expires" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:97 +msgid "These emails can be enabled, disabled and customised under the %sWooCommerce > Settings > Emails%s administration screen." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:99 +msgid "View Email Settings" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:100 +msgctxt "learn more link to subscription emails documentation" +msgid "Learn More" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:108 +msgid "But wait, there's more!" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:109 +msgid "That's not all we've working on for the last 12 months when it comes to Subscriptions. We've also released mini-extensions to help you get the most from your subscription store." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:115 +msgid "Subscription Gifting" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:116 +msgid "What happens when a customer wants to purchase a subscription product for someone else?" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:117 +msgid "The Gifting extension makes it possible for one person to purchase a subscription product for someone else. It then shares control of the subscription between the purchaser and recipient, allowing both to manage the subscription over its lifecycle." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:126 +msgctxt "h3 on the About Subscriptions page for this new feature" +msgid "Import/Export Subscriptions" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:127 +msgid "Import subscriptions to WooCommerce via CSV, or export your subscriptions from WooCommerce to a CSV with the WooCommerce Subscriptions Importer/Exporter extension." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:128 +msgid "This free extension makes it possible to migrate subscribers from 3rd party systems to WooCommerce. It also makes it possible to export your subscription data for analysis in spreadsheet tools or 3rd party apps." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:137 +msgid "Subscribe All the Things" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:138 +msgid "Want your customers to be able to subscribe to non-subscription products?" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:139 +msgid "With WooCommerce Subscribe All the Things, they can! This experimental extension is exploring how to convert any product, including Product Bundles and Composite Products, into a subscription product. It also offers customers a way to subscribe to a cart of non-subscription products." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:157 +msgid "Customise Retry Rules" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:159 +msgid "The best part about the new automatic retry system is that the retry rules are completely customisable." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: includes/upgrades/templates/wcs-about.php:162 +msgid "With the %s'wcs_default_retry_rules'%s filter, you can define a set of default rules to apply to all failed payments in your store." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: includes/upgrades/templates/wcs-about.php:166 +msgid "To apply a specific rule based on certain conditions, like high value orders or an infrequent renewal schedule, you can use the retry specific %s'wcs_get_retry_rule'%s filter. This provides the ID of the renewal order for the failed payment, which can be used to find information about the products, subscription and totals to which the failed payment relates." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:174 +msgid "WP REST API Endpoints" +msgstr "" + +#. translators: $1: opening tag linking to WC API docs, $2: closing tag, $3: opening tag linking to WP API docs, $4: closing tag +#: includes/upgrades/templates/wcs-about.php:177 +msgid "WooCommerce 2.6 added support for %1$sREST API%2$s endpoints built on WordPress core's %3$sREST API%4$s infrastructure." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:179 +msgid "Subscriptions 2.1 adds support for subscription data to this infrastructure." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:180 +msgid "Your applications can now create, read, update or delete subscriptions via RESTful API endpoints with the same design as the latest version of WooCommerce's REST API endpoints." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: includes/upgrades/templates/wcs-about.php:183 +msgid "Want to list all the subscriptions on a site? Get %s/wp-json/wc/v1/subscriptions%s." +msgstr "" + +#. translators: all placeholders are opening and closing tags, no need to order them +#: includes/upgrades/templates/wcs-about.php:187 +msgid "Want the details of a specific subscription? Get %s/wp-json/wc/v1/subscriptions//%s." +msgstr "" + +#. translators: placeholders are opening and closing code tags +#: includes/upgrades/templates/wcs-about.php:197 +msgid "Honour Renewal Order Data" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:199 +msgid "In previous versions of Subscriptions, the subscription total was passed to payment gateways as the amount to charge for automatic renewal payments. This made it unnecessarily complicated to add one-time fees or discounts to a renewal." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:202 +msgid "Subscriptions 2.1 now passes the renewal order's total, making it possible to add a fee or discount to the renewal order with simple one-liners like %s$order->add_fee()%s or %s$order->add_coupon()%s." +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-about.php:206 +msgid "Subscriptions also now uses the renewal order to setup the cart for %smanual renewals%s, making it easier to add products or discounts to a single renewal paid manually." +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:212 +msgid "See the full guide to What's New in Subscriptions version 2.1 »" +msgstr "" + +#: includes/upgrades/templates/wcs-about.php:213 +msgid "Go to WooCommerce Subscriptions Settings »" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:24 +msgid "WooCommerce Subscriptions Update in Progress" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:30 +msgid "The Upgrade is in Progress" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:31 +msgid "The WooCommerce Subscriptions plugin is currently running its database upgrade routine." +msgstr "" + +#. translators: placeholder is number of seconds +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:34 +msgid "If you received a server error and reloaded the page to find this notice, please refresh the page in %s seconds and the upgrade routine will recommence without issues." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade-in-progress.php:36 +msgid "Rest assured, although the update process may take a little while, it is coded to prevent defects, your site is safe and will be up and running again, faster than ever, shortly." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:19 +msgid "WooCommerce Subscriptions Update" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:29 +msgid "Database Update Required" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:30 +msgid "The WooCommerce Subscriptions plugin has been updated!" +msgstr "" + +#. translators: placeholders are opening and closing tags +#: includes/upgrades/templates/wcs-upgrade.php:33 +msgid "Before we send you on your way, we need to update your database to the newest version. If you do not have a recent backup of your site, %snow is the time to create one%s." +msgstr "" + +#. translators: 1$: number of subscriptions on site, 2$, lower estimate (minutes), 3$: upper estimate +#: includes/upgrades/templates/wcs-upgrade.php:38 +msgid "The full update process for the %1$d subscriptions on your site will take between %2$d and %3$d minutes." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:41 +msgid "The update process may take a little while, so please be patient." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:43 +msgid "Customers and other non-administrative users can browse and purchase from your store without interruption while the update is in progress." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:45 +msgctxt "text on submit button" +msgid "Update Database" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:49 +msgid "Update in Progress" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:50 +msgid "This page will display the results of the process as each batch of subscriptions is updated." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:51 +msgid "Please keep this page open until the update process completes. No need to refresh or restart the process." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:53 +msgid "Remember, although the update process may take a while, customers and other non-administrative users can browse and purchase from your store without interruption while the update is in progress." +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:61 +msgid "Update Complete" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:62 +msgid "Your database has been updated successfully!" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:63 +msgid "Continue" +msgstr "" + +#. translators: $1: placeholder is number of weeks, 2$: path to the file +#: includes/upgrades/templates/wcs-upgrade.php:66 +msgid "To record the progress of the update a new log file was created. This file will be automatically deleted in %1$d weeks. If you would like to delete it sooner, you can find it here: %2$s" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:71 +msgid "Update Error" +msgstr "" + +#: includes/upgrades/templates/wcs-upgrade.php:72 +msgid "There was an error with the update. Please refresh the page and try again." +msgstr "" + +#. translators: %s: shipping method label. +#: includes/wcs-cart-functions.php:98 +#: includes/wcs-cart-functions.php:104 +msgid "Shipping via %s" +msgstr "" + +#: includes/wcs-cart-functions.php:239 +msgctxt "shipping method price" +msgid "Free" +msgstr "" + +#: includes/wcs-cart-functions.php:264 +msgid "[Remove]" +msgstr "" + +#: includes/wcs-cart-functions.php:294 +msgid "Free shipping coupon" +msgstr "" + +#. translators: placeholder is price string, denotes tax included in cart/order total +#: includes/wcs-cart-functions.php:332 +msgctxt "includes tax" +msgid "(includes %s)" +msgstr "" + +#. translators: placeholder is a date +#: includes/wcs-cart-functions.php:407 +msgid "First renewal: %s" +msgstr "" + +#. translators: placeholder is either subscription key or a subscription id, or, failing that, empty (e.g. "145_21" or "145") +#: includes/wcs-deprecated-functions.php:180 +msgid "Could not get subscription. Most likely the subscription key does not refer to a subscription. The key was: \"%s\"." +msgstr "" + +#: includes/wcs-formatting-functions.php:41 +msgctxt "initial payment on a subscription" +msgid "up front" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount string (e.g. "£10 / month" ) +#: includes/wcs-formatting-functions.php:99 +msgid "%1$s %2$s then %3$s" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount string, 4$: payment day of the week (e.g. "$15 up front, then $10 every Wednesday") +#: includes/wcs-formatting-functions.php:113 +msgid "%1$s %2$s then %3$s every %4$s" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front" ), 3$: recurring amount, 4$: interval (e.g. "2nd week"), 5$: day of the week (e.g. "Thursday"); (e.g. "$10 up front, then $20 every 2nd week on Wednesday") +#: includes/wcs-formatting-functions.php:122 +msgid "%1$s %2$s then %3$s every %4$s on %5$s" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount; (e.g. "$10 up front then $30 on the last day of each month") +#: includes/wcs-formatting-functions.php:135 +msgid "%1$s %2$s then %3$s on the last day of each month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up front then $40 on the 23rd of each month") +#: includes/wcs-formatting-functions.php:138 +msgid "%1$s %2$s then %3$s on the %4$s of each month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:154 +msgid "%1$s %2$s then %3$s on the last day of every %4$s month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:157 +msgid "%1$s %2$s then %3$s on the %4$s day of every %5$s month" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month (e.g. "23rd") +#: includes/wcs-formatting-functions.php:175 +msgid "%1$s %2$s then %3$s on %4$s %5$s each year" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g. "23rd"), 6$: interval (e.g. "3rd") +#: includes/wcs-formatting-functions.php:184 +msgid "%1$s %2$s then %3$s on %4$s %5$s every %6$s year" +msgstr "" + +#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"), 3$: recurring amount, 4$: subscription period (e.g. "month" or "3 months") +#: includes/wcs-formatting-functions.php:194 +msgid "%1$s %2$s then %3$s / %4$s" +msgid_plural "%1$s %2$s then %3$s every %4$s" +msgstr[0] "" +msgstr[1] "" + +#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: trial length (e.g. "3 weeks") +#: includes/wcs-formatting-functions.php:216 +msgid "%1$s after %2$s free trial" +msgstr "" + +#. translators: 1$: trial length (e.g. "3 weeks"), 2$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year") +#: includes/wcs-formatting-functions.php:219 +msgid "%1$s free trial then %2$s" +msgstr "" + +#. translators: placeholder is human time diff (e.g. "3 weeks") +#: includes/wcs-formatting-functions.php:243 +msgid "in %s" +msgstr "" + +#. translators: placeholder is a localized date and time (e.g. "February 1, 2018 10:20 PM") +#: includes/wcs-formatting-functions.php:251 +msgctxt "wcs_get_human_time_diff" +msgid "%s" +msgstr "" + +#. translators: date placeholder for input, javascript format +#: includes/wcs-helper-functions.php:40 +msgid "YYYY-MM-DD" +msgstr "" + +#. translators: hour placeholder for time input, javascript format +#: includes/wcs-helper-functions.php:45 +msgid "HH" +msgstr "" + +#. translators: minute placeholder for time input, javascript format +#: includes/wcs-helper-functions.php:48 +msgid "MM" +msgstr "" + +#. translators: 1) passed sort order type argument, 2) 'ascending', 3) 'descending'. +#: includes/wcs-helper-functions.php:266 +msgid "Invalid sort order type: %1$s. The $sort_order argument must be %2$s or %3$s." +msgstr "" + +#: includes/wcs-order-functions.php:148 +msgctxt "In wcs_copy_order_meta error message. Refers to origin and target order objects." +msgid "Invalid data. Orders expected aren't orders." +msgstr "" + +#: includes/wcs-order-functions.php:152 +msgctxt "Refers to the type of the copy being performed: \"copy_order\", \"subscription\", \"renewal_order\", \"resubscribe_order\"" +msgid "Invalid data. Type of copy is not a string." +msgstr "" + +#. translators: placeholders are strftime() strings. +#. translators: Order date parsed by strftime +#: includes/wcs-order-functions.php:296 +#: wcs-functions.php:161 +msgctxt "Used in subscription post title. \"Subscription renewal order - \"" +msgid "%b %d, %Y @ %I:%M %p" +msgstr "" + +#. translators: placeholder is a date. +#: includes/wcs-order-functions.php:301 +msgid "Subscription Renewal Order – %s" +msgstr "" + +#. translators: placeholder is a date. +#: includes/wcs-order-functions.php:305 +msgid "Resubscribe Order – %s" +msgstr "" + +#: includes/wcs-order-functions.php:324 +msgid "$type passed to the function was not a string." +msgstr "" + +#. translators: placeholder is an order type. +#: includes/wcs-order-functions.php:329 +msgid "\"%s\" is not a valid new order type." +msgstr "" + +#: includes/wcs-order-functions.php:519 +msgid "Invalid data. No valid subscription / order was passed in." +msgstr "" + +#: includes/wcs-order-functions.php:523 +msgid "Invalid data. No valid item id was passed in." +msgstr "" + +#. translators: placeholder is number of days. (e.g. "Bill this every day / 4 days") +#: includes/wcs-time-functions.php:31 +msgctxt "Subscription billing period." +msgid "day" +msgid_plural "%s days" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 weeks") +#: includes/wcs-time-functions.php:33 +msgctxt "Subscription billing period." +msgid "week" +msgid_plural "%s weeks" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is number of months. (e.g. "Bill this every month / 4 months") +#: includes/wcs-time-functions.php:35 +msgctxt "Subscription billing period." +msgid "month" +msgid_plural "%s months" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is number of years. (e.g. "Bill this every year / 4 years") +#: includes/wcs-time-functions.php:37 +msgctxt "Subscription billing period." +msgid "year" +msgid_plural "%s years" +msgstr[0] "" +msgstr[1] "" + +#: includes/wcs-time-functions.php:88 +msgctxt "Subscription length" +msgid "Never expire" +msgstr "" + +#: includes/wcs-time-functions.php:93 +msgctxt "Subscription lengths. e.g. \"For 1 day...\"" +msgid "1 day" +msgstr "" + +#: includes/wcs-time-functions.php:97 +msgctxt "Subscription lengths. e.g. \"For 1 week...\"" +msgid "1 week" +msgstr "" + +#: includes/wcs-time-functions.php:101 +msgctxt "Subscription lengths. e.g. \"For 1 month...\"" +msgid "1 month" +msgstr "" + +#: includes/wcs-time-functions.php:105 +msgctxt "Subscription lengths. e.g. \"For 1 year...\"" +msgid "1 year" +msgstr "" + +#: includes/wcs-time-functions.php:159 +msgctxt "period interval (eg \"$10 _every_ 2 weeks\")" +msgid "every" +msgstr "" + +#. translators: period interval, placeholder is ordinal (eg "$10 every _2nd/3rd/4th_", etc) +#: includes/wcs-time-functions.php:163 +msgctxt "period interval with ordinal number (e.g. \"every 2nd\"" +msgid "every %s" +msgstr "" + +#: includes/wcs-time-functions.php:188 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: includes/wcs-time-functions.php:189 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "week" +msgid_plural "weeks" +msgstr[0] "" +msgstr[1] "" + +#: includes/wcs-time-functions.php:190 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "month" +msgid_plural "months" +msgstr[0] "" +msgstr[1] "" + +#: includes/wcs-time-functions.php:191 +msgctxt "Used in the trial period dropdown. Number is in text field. 0, 2+ will need plural, 1 will need singular." +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#: includes/wcs-time-functions.php:210 +msgctxt "no trial period" +msgid "no" +msgstr "" + +#: includes/wcs-user-functions.php:345 +#: templates/single-product/add-to-cart/subscription.php:30 +#: templates/single-product/add-to-cart/variable-subscription.php:28 +msgid "Resubscribe" +msgstr "" + +#. translators: placeholder is a currency symbol / code +#: templates/admin/deprecated/html-variation-price.php:20 +#: templates/admin/deprecated/html-variation-price.php:30 +msgid "Subscription Price (%s)" +msgstr "" + +#: templates/admin/deprecated/html-variation-price.php:46 +msgid "Subscription Periods" +msgstr "" + +#: templates/admin/deprecated/html-variation-price.php:59 +msgctxt "Edit product screen, between the Billing Period and Subscription Length dropdowns" +msgid "for" +msgstr "" + +#: templates/admin/deprecated/html-variation-price.php:69 +msgid "Subscription Length" +msgstr "" + +#: templates/admin/deprecated/html-variation-price.php:85 +msgid "Sign-up Fee (%s)" +msgstr "" + +#: templates/admin/deprecated/html-variation-price.php:97 +#: templates/admin/deprecated/html-variation-price.php:104 +msgid "Free Trial" +msgstr "" + +#: templates/admin/deprecated/html-variation-price.php:105 +msgctxt "example number of days / weeks / months" +msgid "e.g. 3" +msgstr "" + +#. translators: placeholder is trial period validation message if passed an invalid value (e.g. "Trial period can not exceed 4 weeks") +#: templates/admin/deprecated/html-variation-price.php:118 +#: templates/admin/html-variation-price.php:27 +msgctxt "Trial period dropdown's description in pricing fields" +msgid "An optional period of time to wait before charging the first recurring payment. Any sign up fee will still be charged at the outset of the subscription. %s" +msgstr "" + +#: templates/admin/deprecated/html-variation-synchronisation.php:30 +msgid "Synchronise Renewals" +msgstr "" + +#: templates/admin/deprecated/order-shipping-html.php:8 +msgid "Label" +msgstr "" + +#: templates/admin/deprecated/order-shipping-html.php:13 +msgid "Shipping Method" +msgstr "" + +#: templates/admin/deprecated/order-shipping-html.php:34 +#: templates/admin/deprecated/order-shipping-html.php:36 +msgid "Other" +msgstr "" + +#: templates/admin/deprecated/order-tax-html.php:17 +msgid "Recurring Sales Tax:" +msgstr "" + +#: templates/admin/deprecated/order-tax-html.php:21 +msgid "Shipping Tax:" +msgstr "" + +#: templates/admin/html-failed-scheduled-action-notice.php:21 +msgid "An error has occurred while processing a recent subscription related event. For steps on how to fix the affected subscription and to learn more about the possible causes of this error, please read our guide %1$shere%2$s." +msgid_plural "An error has occurred while processing recent subscription related events. For steps on how to fix the affected subscriptions and to learn more about the possible causes of this error, please read our guide %1$shere%2$s." +msgstr[0] "" +msgstr[1] "" + +#: templates/admin/html-failed-scheduled-action-notice.php:31 +msgid "Affected event:" +msgid_plural "Affected events:" +msgstr[0] "" +msgstr[1] "" + +#. translators: $1 the log file name $2 and $3 are opening and closing link tags, respectively. +#: templates/admin/html-failed-scheduled-action-notice.php:38 +msgid "To see further details about these errors, view the %1$s log file from the %2$sWooCommerce logs screen.%2$s" +msgstr "" + +#: templates/admin/html-variation-price.php:31 +msgid "Subscription trial period:" +msgstr "" + +#: templates/admin/html-variation-price.php:49 +msgid "Billing interval:" +msgstr "" + +#: templates/admin/html-variation-price.php:56 +msgid "Billing Period:" +msgstr "" + +#: templates/admin/html-variation-price.php:67 +msgctxt "Subscription Length dropdown's description in pricing fields" +msgid "Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date." +msgstr "" + +#: templates/cart/cart-recurring-shipping.php:32 +msgid "Shipping costs will be calculated once you have provided your address." +msgstr "" + +#: templates/cart/cart-recurring-shipping.php:34 +msgid "There are no shipping methods available. Please double check your address, or contact us if you need any help." +msgstr "" + +#: templates/checkout/form-change-payment-method.php:20 +#: templates/emails/email-order-details.php:36 +#: templates/myaccount/subscription-totals-table.php:21 +msgctxt "table headings in notification email" +msgid "Product" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:21 +#: templates/emails/email-order-details.php:37 +msgctxt "table headings in notification email" +msgid "Quantity" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:22 +msgctxt "table headings in notification email" +msgid "Totals" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:47 +msgctxt "text on button on checkout page" +msgid "Change payment method" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:49 +msgctxt "text on button on checkout page" +msgid "Add payment method" +msgstr "" + +#: templates/checkout/form-change-payment-method.php:82 +msgid "Sorry, it seems no payment gateways support changing the recurring payment method. Please contact us if you require assistance or to make alternate arrangements." +msgstr "" + +#. translators: $1: opening tag, $2: closing tag +#: templates/checkout/form-change-payment-method.php:91 +msgid "Update the payment method used for %1$sall%2$s of my current subscriptions" +msgstr "" + +#: templates/checkout/recurring-subscription-totals.php:18 +#: templates/checkout/recurring-subscription-totals.php:19 +msgid "Recurring total" +msgstr "" + +#: templates/checkout/recurring-subtotals.php:18 +#: templates/checkout/recurring-subtotals.php:19 +msgid "Subtotal" +msgstr "" + +#: templates/checkout/recurring-totals.php:17 +msgid "Recurring totals" +msgstr "" + +#. translators: placeholder is the subscription order number wrapped in tags +#: templates/checkout/subscription-receipt.php:18 +#: templates/emails/plain/email-order-details.php:19 +msgid "Subscription Number: %s" +msgstr "" + +#. translators: placeholder is the subscription's next payment date (either human readable or normal date) wrapped in tags +#: templates/checkout/subscription-receipt.php:24 +msgid "Next Payment Date: %s" +msgstr "" + +#. translators: placeholder is the formatted total to be paid for the subscription wrapped in tags +#: templates/checkout/subscription-receipt.php:30 +msgid "Total: %s" +msgstr "" + +#. translators: placeholder is the display name of the payment method +#: templates/checkout/subscription-receipt.php:37 +msgid "Payment Method: %s" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/admin-new-renewal-order.php:16 +#: templates/emails/plain/admin-new-renewal-order.php:16 +msgctxt "Used in admin email: new renewal order" +msgid "You have received a subscription renewal order from %1$s. Their order is as follows:" +msgstr "" + +#. translators: $1: customer's first name and last name, $2: how many subscriptions customer switched +#: templates/emails/admin-new-switch-order.php:18 +#: templates/emails/plain/admin-new-switch-order.php:18 +msgctxt "Used in switch notification admin email" +msgid "Customer %1$s has switched their subscription. The details of their new subscription are as follows:" +msgid_plural "Customer %1$s has switched %2$d of their subscriptions. The details of their new subscriptions are as follows:" +msgstr[0] "" +msgstr[1] "" + +#: templates/emails/admin-new-switch-order.php:20 +msgid "Switch Order Details" +msgstr "" + +#: templates/emails/admin-new-switch-order.php:28 +#: templates/emails/customer-completed-switch-order.php:26 +msgid "New subscription details" +msgstr "" + +#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: templates/emails/admin-payment-retry.php:23 +msgctxt "In customer renewal invoice email" +msgid "The automatic recurring payment for order #%d from %s has failed. The payment will be retried %3$s." +msgstr "" + +#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: templates/emails/admin-payment-retry.php:24 +#: templates/emails/plain/admin-payment-retry.php:21 +msgid "The renewal order is as follows:" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/cancelled-subscription.php:16 +#: templates/emails/plain/cancelled-subscription.php:16 +msgid "A subscription belonging to %1$s has been cancelled. Their subscription's details are as follows:" +msgstr "" + +#: templates/emails/cancelled-subscription.php:22 +#: templates/emails/email-order-details.php:38 +#: templates/emails/expired-subscription.php:22 +#: templates/emails/on-hold-subscription.php:22 +msgctxt "table headings in notification email" +msgid "Price" +msgstr "" + +#: templates/emails/cancelled-subscription.php:23 +#: templates/emails/expired-subscription.php:23 +#: templates/emails/on-hold-subscription.php:23 +#: wcs-functions.php:306 +msgctxt "table heading" +msgid "Last Order Date" +msgstr "" + +#: templates/emails/cancelled-subscription.php:24 +msgctxt "table headings in notification email" +msgid "End of Prepaid Term" +msgstr "" + +#: templates/emails/cancelled-subscription.php:41 +#: templates/emails/expired-subscription.php:41 +#: templates/emails/on-hold-subscription.php:41 +msgid "-" +msgstr "" + +#. translators: %s: Customer first name +#: templates/emails/customer-completed-renewal-order.php:17 +#: templates/emails/customer-completed-switch-order.php:17 +#: templates/emails/customer-on-hold-renewal-order.php:17 +#: templates/emails/customer-payment-retry.php:16 +#: templates/emails/customer-processing-renewal-order.php:17 +#: templates/emails/customer-renewal-invoice.php:16 +#: templates/emails/plain/customer-completed-renewal-order.php:16 +#: templates/emails/plain/customer-completed-switch-order.php:16 +#: templates/emails/plain/customer-on-hold-renewal-order.php:16 +#: templates/emails/plain/customer-payment-retry.php:16 +#: templates/emails/plain/customer-processing-renewal-order.php:16 +#: templates/emails/plain/customer-renewal-invoice.php:16 +msgid "Hi %s," +msgstr "" + +#: templates/emails/customer-completed-renewal-order.php:18 +#: templates/emails/plain/customer-completed-renewal-order.php:17 +msgid "We have finished processing your subscription renewal order." +msgstr "" + +#: templates/emails/customer-completed-switch-order.php:18 +#: templates/emails/plain/customer-completed-switch-order.php:17 +msgid "You have successfully changed your subscription items. Your new order and subscription details are shown below for your reference:" +msgstr "" + +#: templates/emails/customer-on-hold-renewal-order.php:18 +#: templates/emails/plain/customer-on-hold-renewal-order.php:17 +msgid "Thanks for your renewal order. It’s on-hold until we confirm that payment has been received. In the meantime, here’s a reminder of your order:" +msgstr "" + +#. translators: %s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: templates/emails/customer-payment-retry.php:18 +#: templates/emails/plain/customer-payment-retry.php:18 +msgctxt "In customer renewal invoice email" +msgid "The automatic payment to renew your subscription has failed. We will retry the payment %s." +msgstr "" + +#. translators: %1$s %2$s: link markup to checkout payment url, note: no full stop due to url at the end +#: templates/emails/customer-payment-retry.php:21 +msgctxt "In customer renewal invoice email" +msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$sPay Now »%2$s" +msgstr "" + +#. translators: %s: Order number +#: templates/emails/customer-processing-renewal-order.php:19 +#: templates/emails/plain/customer-processing-renewal-order.php:18 +msgid "Just to let you know — we've received your subscription renewal order #%s, and it is now being processed:" +msgstr "" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end +#: templates/emails/customer-renewal-invoice.php:22 +#: templates/emails/plain/customer-renewal-invoice.php:20 +msgctxt "In customer renewal invoice email" +msgid "An order has been created for you to renew your subscription on %1$s. To pay for this invoice please use the following link: %2$s" +msgstr "" + +#: templates/emails/customer-renewal-invoice.php:24 +#: templates/emails/customer-renewal-invoice.php:33 +msgid "Pay Now »" +msgstr "" + +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end +#: templates/emails/customer-renewal-invoice.php:31 +#: templates/emails/plain/customer-renewal-invoice.php:23 +msgctxt "In customer renewal invoice email" +msgid "The automatic payment to renew your subscription with %1$s has failed. To reactivate the subscription, please log in and pay for the renewal from your account page: %2$s" +msgstr "" + +#. translators: $1-$2: opening and closing tags $3: order's order number $4: date of order in tags $2: subscription's order number +#: templates/emails/email-order-details.php:27 +msgctxt "Used in email notification" +msgid "Subscription %1$s#%2$s%3$s" +msgstr "" + +#: templates/emails/email-order-details.php:61 +msgid "Note:" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/expired-subscription.php:16 +#: templates/emails/plain/expired-subscription.php:16 +msgid "A subscription belonging to %1$s has expired. Their subscription's details are as follows:" +msgstr "" + +#: templates/emails/expired-subscription.php:24 +msgctxt "table headings in notification email" +msgid "End Date" +msgstr "" + +#. translators: $1: customer's billing first name and last name +#: templates/emails/on-hold-subscription.php:16 +#: templates/emails/plain/on-hold-subscription.php:16 +msgid "A subscription belonging to %1$s has been suspended by the user. Their subscription's details are as follows:" +msgstr "" + +#: templates/emails/on-hold-subscription.php:24 +msgctxt "table headings in notification email" +msgid "Date Suspended" +msgstr "" + +#. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' +#: templates/emails/plain/admin-payment-retry.php:20 +msgctxt "In customer renewal invoice email" +msgid "The automatic recurring payment for order #%1$s from %2$s has failed. The payment will be retried %3$s." +msgstr "" + +#. translators: placeholder is last time subscription was paid +#: templates/emails/plain/cancelled-subscription.php:32 +#: templates/emails/plain/expired-subscription.php:32 +msgid "Last Order Date: %s" +msgstr "" + +#. translators: placeholder is localised date string +#: templates/emails/plain/cancelled-subscription.php:39 +msgid "End of Prepaid Term: %s" +msgstr "" + +#: templates/emails/plain/cancelled-subscription.php:44 +#: templates/emails/plain/expired-subscription.php:44 +#: templates/emails/plain/on-hold-subscription.php:40 +msgctxt "in plain emails for subscription information" +msgid "View Subscription: %s" +msgstr "" + +#. translators: placeholder is order's view url +#: templates/emails/plain/customer-completed-switch-order.php:24 +msgid "View your order: %s" +msgstr "" + +#. translators: placeholder is subscription's view url +#: templates/emails/plain/customer-completed-switch-order.php:35 +msgid "View your subscription: %s" +msgstr "" + +#. translators: %1$s: link to checkout payment url, note: no full stop due to url at the end +#: templates/emails/plain/customer-payment-retry.php:21 +msgctxt "In customer renewal invoice email" +msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$s" +msgstr "" + +#: templates/emails/plain/email-order-details.php:16 +msgid "Order number: %s" +msgstr "" + +#: templates/emails/plain/email-order-details.php:17 +msgid "Order date: %s" +msgstr "" + +#. translators: placeholder is localised date string +#: templates/emails/plain/expired-subscription.php:39 +msgid "End Date: %s" +msgstr "" + +#. translators: placeholder is last time subscription was paid +#: templates/emails/plain/on-hold-subscription.php:32 +msgid "Last Order: %s" +msgstr "" + +#. translators: placeholder is localised date string +#: templates/emails/plain/on-hold-subscription.php:36 +msgid "Date Suspended: %s" +msgstr "" + +#: templates/emails/plain/subscription-info.php:20 +#: templates/emails/subscription-info.php:21 +msgid "Subscription information" +msgstr "" + +#. translators: placeholder is subscription's number +#: templates/emails/plain/subscription-info.php:25 +msgctxt "in plain emails for subscription information" +msgid "Subscription: %s" +msgstr "" + +#. translators: placeholder is either view or edit url for the subscription +#: templates/emails/plain/subscription-info.php:27 +msgctxt "in plain emails for subscription information" +msgid "View subscription: %s" +msgstr "" + +#. translators: placeholder is localised start date +#: templates/emails/plain/subscription-info.php:29 +msgctxt "in plain emails for subscription information" +msgid "Start date: %s" +msgstr "" + +#: templates/emails/plain/subscription-info.php:31 +msgctxt "Used as end date for an indefinite subscription" +msgid "When Cancelled" +msgstr "" + +#. translators: placeholder is localised end date, or "when cancelled" +#: templates/emails/plain/subscription-info.php:33 +msgctxt "in plain emails for subscription information" +msgid "End date: %s" +msgstr "" + +#. translators: placeholder is the formatted order total for the subscription +#: templates/emails/plain/subscription-info.php:35 +msgctxt "in plain emails for subscription information" +msgid "Recurring price: %s" +msgstr "" + +#: templates/emails/plain/subscription-info.php:38 +#: templates/emails/subscription-info.php:42 +msgid "Next payment: %s" +msgstr "" + +#. Translators: Placeholder is the My Account URL. +#: templates/emails/plain/subscription-info.php:52 +msgid "This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your my account page. %s" +msgid_plural "These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your my account page. %s" +msgstr[0] "" +msgstr[1] "" + +#: templates/emails/subscription-info.php:25 +msgctxt "subscription ID table heading" +msgid "ID" +msgstr "" + +#: templates/emails/subscription-info.php:26 +msgctxt "table heading" +msgid "Start date" +msgstr "" + +#: templates/emails/subscription-info.php:27 +msgctxt "table heading" +msgid "End date" +msgstr "" + +#: templates/emails/subscription-info.php:28 +msgctxt "table heading" +msgid "Recurring total" +msgstr "" + +#: templates/emails/subscription-info.php:35 +msgctxt "subscription number in email table. (eg: #106)" +msgid "#%s" +msgstr "" + +#: templates/emails/subscription-info.php:37 +msgctxt "Used as end date for an indefinite subscription" +msgid "When cancelled" +msgstr "" + +#. Translators: Placeholders are opening and closing My Account link tags. +#: templates/emails/subscription-info.php:58 +msgid "This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your %smy account page%s." +msgid_plural "These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your %smy account page%s." +msgstr[0] "" +msgstr[1] "" + +#: templates/html-early-renewal-modal-content.php:23 +msgid "By renewing your subscription early your next payment will be %s." +msgstr "" + +#: templates/html-early-renewal-modal-content.php:28 +msgid "By renewing your subscription early, your scheduled next payment on %s will be cancelled." +msgstr "" + +#: templates/html-early-renewal-modal-content.php:34 +msgid "Want to renew early via the checkout? Click %shere.%s" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:23 +#: templates/myaccount/related-subscriptions.php:23 +#: templates/myaccount/related-subscriptions.php:39 +msgctxt "table heading" +msgid "Next payment" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:33 +#: templates/myaccount/related-subscriptions.php:31 +msgid "ID" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:40 +#: wcs-functions.php:305 +msgctxt "table heading" +msgid "Next Payment" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:46 +#: templates/myaccount/related-orders.php:53 +#: templates/myaccount/related-subscriptions.php:42 +msgctxt "Used in data attribute. Escaped" +msgid "Total" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:50 +#: templates/myaccount/related-orders.php:84 +#: templates/myaccount/related-subscriptions.php:46 +msgctxt "view a subscription" +msgid "View" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:61 +msgid "Previous" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:65 +msgid "Next" +msgstr "" + +#: templates/myaccount/my-subscriptions.php:72 +msgid "You have reached the end of subscriptions. Go to the %sfirst page%s." +msgstr "" + +#: templates/myaccount/my-subscriptions.php:74 +msgid "You have no active subscriptions." +msgstr "" + +#: templates/myaccount/my-subscriptions.php:77 +msgid "Browse products" +msgstr "" + +#: templates/myaccount/related-orders.php:15 +msgid "Related orders" +msgstr "" + +#: templates/myaccount/related-orders.php:22 +msgid "Order" +msgstr "" + +#. translators: $1: formatted order total for the order, $2: number of items bought +#: templates/myaccount/related-orders.php:56 +msgid "%1$s for %2$d item" +msgid_plural "%1$s for %2$d items" +msgstr[0] "" +msgstr[1] "" + +#: templates/myaccount/related-orders.php:65 +msgctxt "pay for a subscription" +msgid "Pay" +msgstr "" + +#: templates/myaccount/related-subscriptions.php:15 +msgid "Related subscriptions" +msgstr "" + +#: templates/myaccount/subscription-details.php:24 +msgctxt "customer subscription table header" +msgid "Start date" +msgstr "" + +#: templates/myaccount/subscription-details.php:25 +msgctxt "customer subscription table header" +msgid "Last order date" +msgstr "" + +#: templates/myaccount/subscription-details.php:26 +msgctxt "customer subscription table header" +msgid "Next payment date" +msgstr "" + +#: templates/myaccount/subscription-details.php:27 +msgctxt "customer subscription table header" +msgid "End date" +msgstr "" + +#: templates/myaccount/subscription-details.php:28 +msgctxt "customer subscription table header" +msgid "Trial end date" +msgstr "" + +#: templates/myaccount/subscription-details.php:42 +msgid "Auto renew" +msgstr "" + +#: templates/myaccount/subscription-details.php:50 +msgid "Enable auto renew" +msgstr "" + +#: templates/myaccount/subscription-details.php:57 +msgid "Disable auto renew" +msgstr "" + +#: templates/myaccount/subscription-details.php:62 +msgid "Using the auto-renewal toggle is disabled while in staging mode." +msgstr "" + +#: templates/myaccount/subscription-details.php:71 +msgid "Payment" +msgstr "" + +#: templates/myaccount/subscription-details.php:81 +msgid "Actions" +msgstr "" + +#: templates/myaccount/subscription-details.php:94 +msgid "Subscription updates" +msgstr "" + +#: templates/myaccount/subscription-details.php:100 +msgctxt "date on subscription updates list. Will be localized" +msgid "l jS \\o\\f F Y, h:ia" +msgstr "" + +#: templates/myaccount/subscription-totals-table.php:35 +msgid "Are you sure you want remove this item from your subscription?" +msgstr "" + +#: templates/myaccount/subscription-totals.php:23 +msgid "Subscription totals" +msgstr "" + +#: templates/single-product/add-to-cart/subscription.php:32 +#: templates/single-product/add-to-cart/variable-subscription.php:30 +msgid "You have an active subscription to this product already." +msgstr "" + +#: templates/single-product/add-to-cart/variable-subscription.php:23 +msgid "This product is currently out of stock and unavailable." +msgstr "" + +#: templates/single-product/add-to-cart/variable-subscription.php:34 +msgid "You have added a variation of this product to the cart already." +msgstr "" + +#: templates/single-product/add-to-cart/variable-subscription.php:45 +msgid "Clear" +msgstr "" + +#: wcs-functions.php:130 +msgctxt "Error message while creating a subscription" +msgid "Invalid created date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +msgstr "" + +#: wcs-functions.php:132 +msgctxt "Error message while creating a subscription" +msgid "Subscription created date must be before current day." +msgstr "" + +#: wcs-functions.php:137 +msgctxt "Error message while creating a subscription" +msgid "Invalid date. The date must be a string and of the format: \"Y-m-d H:i:s\"." +msgstr "" + +#: wcs-functions.php:142 +msgctxt "Error message while creating a subscription" +msgid "Invalid subscription customer_id." +msgstr "" + +#. translators: placeholder is order date parsed by strftime +#: wcs-functions.php:163 +msgctxt "The post title for the new subscription" +msgid "Subscription – %s" +msgstr "" + +#: wcs-functions.php:234 +msgctxt "Subscription status" +msgid "On hold" +msgstr "" + +#: wcs-functions.php:238 +msgctxt "Subscription status" +msgid "Pending Cancellation" +msgstr "" + +#: wcs-functions.php:254 +msgid "Can not get status name. Status is not a string." +msgstr "" + +#: wcs-functions.php:277 +msgid "Can not get address type display name. Address type is not a string." +msgstr "" + +#: wcs-functions.php:303 +msgctxt "table heading" +msgid "Start Date" +msgstr "" + +#: wcs-functions.php:304 +msgctxt "table heading" +msgid "Trial End" +msgstr "" + +#: wcs-functions.php:307 +msgctxt "table heading" +msgid "Cancelled Date" +msgstr "" + +#: wcs-functions.php:308 +msgctxt "table heading" +msgid "End Date" +msgstr "" + +#: wcs-functions.php:343 +msgid "Date type is not a string." +msgstr "" + +#: wcs-functions.php:345 +msgid "Date type can not be an empty string." +msgstr "" + +#: woocommerce-subscriptions.php:298 +msgctxt "custom post type setting" +msgid "Add Subscription" +msgstr "" + +#: woocommerce-subscriptions.php:299 +msgctxt "custom post type setting" +msgid "Add New Subscription" +msgstr "" + +#: woocommerce-subscriptions.php:300 +msgctxt "custom post type setting" +msgid "Edit" +msgstr "" + +#: woocommerce-subscriptions.php:301 +msgctxt "custom post type setting" +msgid "Edit Subscription" +msgstr "" + +#: woocommerce-subscriptions.php:302 +msgctxt "custom post type setting" +msgid "New Subscription" +msgstr "" + +#: woocommerce-subscriptions.php:303 +#: woocommerce-subscriptions.php:304 +msgctxt "custom post type setting" +msgid "View Subscription" +msgstr "" + +#: woocommerce-subscriptions.php:307 +msgctxt "custom post type setting" +msgid "No Subscriptions found in trash" +msgstr "" + +#: woocommerce-subscriptions.php:308 +msgctxt "custom post type setting" +msgid "Parent Subscriptions" +msgstr "" + +#: woocommerce-subscriptions.php:311 +msgid "This is where subscriptions are stored." +msgstr "" + +#: woocommerce-subscriptions.php:356 +msgid "No Subscriptions found" +msgstr "" + +#: woocommerce-subscriptions.php:358 +msgid "Subscriptions will appear here for you to view and manage once purchased by a customer." +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: woocommerce-subscriptions.php:360 +msgid "%1$sLearn more about managing subscriptions »%2$s" +msgstr "" + +#. translators: placeholders are opening and closing link tags +#: woocommerce-subscriptions.php:362 +msgid "%1$sAdd a subscription product »%2$s" +msgstr "" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:379 +msgctxt "post status label including post count" +msgid "Active (%s)" +msgid_plural "Active (%s)" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:381 +msgctxt "post status label including post count" +msgid "Switched (%s)" +msgid_plural "Switched (%s)" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:383 +msgctxt "post status label including post count" +msgid "Expired (%s)" +msgid_plural "Expired (%s)" +msgstr[0] "" +msgstr[1] "" + +#. translators: placeholder is a post count. +#: woocommerce-subscriptions.php:385 +msgctxt "post status label including post count" +msgid "Pending Cancellation (%s)" +msgid_plural "Pending Cancellation (%s)" +msgstr[0] "" +msgstr[1] "" + +#: woocommerce-subscriptions.php:429 +msgid "To enable automatic renewals for this subscription, you will first need to add a payment method." +msgstr "" + +#: woocommerce-subscriptions.php:429 +msgid "Would you like to add a payment method now?" +msgstr "" + +#. translators: placeholder is a number, this is for the teens +#. translators: placeholder is a number, numbers ending in 4-9, 0 +#: woocommerce-subscriptions.php:721 +#: woocommerce-subscriptions.php:738 +msgid "%sth" +msgstr "" + +#. translators: placeholder is a number, numbers ending in 1 +#: woocommerce-subscriptions.php:726 +msgid "%sst" +msgstr "" + +#. translators: placeholder is a number, numbers ending in 2 +#: woocommerce-subscriptions.php:730 +msgid "%snd" +msgstr "" + +#. translators: placeholder is a number, numbers ending in 3 +#: woocommerce-subscriptions.php:734 +msgid "%srd" +msgstr "" + +#. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, leads to plugins.php in admin +#: woocommerce-subscriptions.php:773 +msgid "%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce plugin%4$s must be active for WooCommerce Subscriptions to work. Please %5$sinstall & activate WooCommerce »%6$s" +msgstr "" + +#. translators: 1$-2$: opening and closing tags, 3$: minimum supported WooCommerce version, 4$-5$: opening and closing link tags, leads to plugin admin +#: woocommerce-subscriptions.php:776 +msgid "%1$sWooCommerce Subscriptions is inactive.%2$s This version of Subscriptions requires WooCommerce %3$s or newer. Please %4$supdate WooCommerce to version %3$s or newer »%5$s" +msgstr "" + +#: woocommerce-subscriptions.php:807 +msgid "Variable Subscription" +msgstr "" + +#. translators: 1-2: opening/closing tags, 3: Subscriptions version. +#: woocommerce-subscriptions.php:904 +msgid "%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce Subscriptions%2$s comes with that plugin's functionality packaged into the core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to avoid any conflicts." +msgstr "" + +#: woocommerce-subscriptions.php:908 +msgid "Installed Plugins" +msgstr "" + +#. translators: 1$-2$: opening and closing tags. 3$-4$: opening and closing link tags for learn more. Leads to duplicate site article on docs. 5$-6$: Opening and closing link to production URL. 7$: Production URL . +#: woocommerce-subscriptions.php:978 +msgid "It looks like this site has moved or is a duplicate site. %1$sWooCommerce Subscriptions%2$s has disabled automatic payments and subscription related emails on this site to prevent duplicate payments from a staging or test environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be the site's URL. %3$sLearn more »%4$s." +msgstr "" + +#: woocommerce-subscriptions.php:991 +msgid "Quit nagging me (but don't enable automatic payments)" +msgstr "" + +#: woocommerce-subscriptions.php:996 +msgid "Enable automatic payments" +msgstr "" + +#: woocommerce-subscriptions.php:1203 +msgid "Support" +msgstr "" + +#. translators: placeholders are opening and closing tags. Leads to docs on version 2 +#: woocommerce-subscriptions.php:1286 +msgid "Warning! Version 2.0 is a major update to the WooCommerce Subscriptions extension. Before updating, please create a backup, update all WooCommerce extensions and test all plugins, custom code and payment gateways with version 2.0 on a staging site. %1$sLearn more about the changes in version 2.0 »%2$s" +msgstr "" + +#. translators: placeholder is Subscriptions version number. +#: woocommerce-subscriptions.php:1302 +msgid "Warning! You are running version %s of WooCommerce Subscriptions plugin code but your database has been upgraded to Subscriptions version 2.0. This will cause major problems on your store." +msgstr "" + +#. translators: opening/closing tags - linked to ticket form. +#: woocommerce-subscriptions.php:1304 +msgid "Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer immediately. If you need assistance, after upgrading to Subscriptions v2.0, please %1$sopen a support ticket%2$s." +msgstr "" + +#: assets/src/js/utils/index.js:8 +#: build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: assets/src/js/utils/index.js:15 +#: build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "week" +msgid_plural "weeks" +msgstr[0] "" +msgstr[1] "" + +#: assets/src/js/utils/index.js:22 +#: build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "month" +msgid_plural "months" +msgstr[0] "" +msgstr[1] "" + +#: assets/src/js/utils/index.js:29 +#: build/index.js:1 +msgctxt "Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular." +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#: assets/src/js/utils/index.js:63 +#: build/index.js:8 +msgid "Daily recurring total" +msgstr "" + +#: assets/src/js/utils/index.js:68 +#: build/index.js:8 +msgid "Weekly recurring total" +msgstr "" + +#: assets/src/js/utils/index.js:73 +#: build/index.js:8 +msgid "Monthly recurring total" +msgstr "" + +#: assets/src/js/utils/index.js:78 +#: build/index.js:8 +msgid "Yearly recurring total" +msgstr "" + +#. translators: %1$s is week, month, year +#: assets/src/js/utils/index.js:87 +#: build/index.js:10 +msgid "Recurring total every 2nd %1$s" +msgstr "" + +#. Translators: %1$s is week, month, year +#: assets/src/js/utils/index.js:97 +#: build/index.js:12 +msgid "Recurring total every 3rd %1$s" +msgstr "" + +#. Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year +#: assets/src/js/utils/index.js:106 +#: build/index.js:14 +msgid "Recurring total every %1$dth %2$s" +msgstr "" + +#. translators: %1$s Product name, %2$s Switch type (upgraded, downgraded, or crossgraded). +#: assets/src/js/utils/index.js:178 +#: build/index.js:19 +msgid "Upgrade" +msgstr "" + +#: assets/src/js/utils/index.js:181 +#: build/index.js:19 +msgid "Downgrade" +msgstr "" + +#: assets/src/js/utils/index.js:184 +#: build/index.js:19 +msgid "Crossgrade" +msgstr "" + +#. translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/", %3$d is the length, %4$s is week, month, year +#: build/index.js:3 +msgid "%1$s %2$s %3$d %4$s" +msgstr "" + +#. translators: %s selected shipping rate (ex: flat rate) +#: build/index.js:4 +msgid "via %s" +msgstr "" + +#. Translators: %1$s is a date. +#: build/index.js:6 +msgid "Due: %1$s" +msgstr "" + +#. Translators: %1$s is a date. +#: build/index.js:8 +msgid "Starting: %1$s" +msgstr "" + +#. Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year +#: build/index.js:14 +msgid "Details" +msgstr "" + +#: build/index.js:14 +msgid "Total due today" +msgstr "" + +#. translators: the word used to describe billing frequency, e.g. "fo1" 1 day or "for" 1 month. +#: build/index.js:15 +msgid "for 1" +msgstr "" + +#. translators: the word used to describe billing frequency, e.g. "for" 6 days or "for" 2 weeks. +#: build/index.js:16 +msgid "for" +msgstr "" + +#. translators: the word used to describe billing frequency, e.g. "every" 6 days or "every" 2 weeks. +#: build/index.js:17 +msgid "every" +msgstr "" + +#. translators: %s Product name. +#: build/index.js:18 +msgid "%s (resubscription)" +msgstr "" + +#. translators: %1$s Product name, %2$s Switch type (upgraded, downgraded, or crossgraded). +#: build/index.js:19 +msgid "%1$s (%2$s)" +msgstr "" + +#. translators: %s is the subscription price to pay immediately (ie: $10). +#: build/index.js:21 +msgid "Due today %s" +msgstr "" + +#. translators: %s is the subscription price to pay immediately (ie: $10). +#: build/index.js:23 +msgid "%s due today" +msgstr "" diff --git a/includes/libraries/action-scheduler/license.txt b/vendor/woocommerce/subscriptions-core/license.txt similarity index 66% rename from includes/libraries/action-scheduler/license.txt rename to vendor/woocommerce/subscriptions-core/license.txt index f288702..407158a 100644 --- a/includes/libraries/action-scheduler/license.txt +++ b/vendor/woocommerce/subscriptions-core/license.txt @@ -1,16 +1,34 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 +WooCommerce Subscriptions Core - Subscriptions core package for WooCommerce +Copyright (C) 2019-2021 by the contributors - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. - Preamble +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - The GNU General Public License is a free, copyleft license for +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + Preamble + +The GNU General Public License is a free, copyleft license for software and other kinds of works. - The licenses for most software and other practical works are designed +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free @@ -19,35 +37,35 @@ GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. - When we speak of free software, we are referring to freedom, not +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - For example, if you distribute copies of such a program, whether +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - Developers that use the GNU GPL protect your rights with two steps: +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - For the developers' and authors' protection, the GPL clearly explains +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - Some devices are designed to deny users access to install or run +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic @@ -58,49 +76,49 @@ products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - Finally, every program is threatened constantly by software patents. +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - The precise terms and conditions for copying, distribution and +The precise terms and conditions for copying, distribution and modification follow. - TERMS AND CONDITIONS + TERMS AND CONDITIONS - 0. Definitions. +0. Definitions. - "This License" refers to version 3 of the GNU General Public License. +"This License" refers to version 3 of the GNU General Public License. - "Copyright" also means copyright-like laws that apply to other kinds of +"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - "The Program" refers to any copyrightable work licensed under this +"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. - To "modify" a work means to copy from or adapt all or part of the work +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. - A "covered work" means either the unmodified Program or a work based +A "covered work" means either the unmodified Program or a work based on the Program. - To "propagate" a work means to do anything with it that, without +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - To "convey" a work means any kind of propagation that enables other +To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - An interactive user interface displays "Appropriate Legal Notices" +An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the @@ -109,18 +127,18 @@ work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - 1. Source Code. +1. Source Code. - The "source code" for a work means the preferred form of the work +The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. - A "Standard Interface" means an interface that either is an official +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - The "System Libraries" of an executable work include anything, other +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that @@ -131,7 +149,7 @@ implementation is available to the public in source code form. A (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - The "Corresponding Source" for a work in object code form means all +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's @@ -144,16 +162,16 @@ linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - The Corresponding Source need not include anything that users +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - The Corresponding Source for a work in source code form is that +The Corresponding Source for a work in source code form is that same work. - 2. Basic Permissions. +2. Basic Permissions. - All rights granted under this License are granted for the term of +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a @@ -161,7 +179,7 @@ covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - You may make, run and propagate covered works that you do not +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you @@ -172,19 +190,19 @@ for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - Conveying under any other circumstances is permitted solely under +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. +3. Protecting Users' Legal Rights From Anti-Circumvention Law. - No covered work shall be deemed part of an effective technological +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - When you convey a covered work, you waive any legal power to forbid +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or @@ -192,9 +210,9 @@ modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - 4. Conveying Verbatim Copies. +4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program's source code as you +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any @@ -202,37 +220,37 @@ non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - You may charge any price or no price for each copy that you convey, +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - 5. Conveying Modified Source Versions. +5. Conveying Modified Source Versions. - You may convey a work based on the Program, or the modifications to +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. +a) The work must carry prominent notices stating that you modified +it, and giving a relevant date. - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". +b) The work must carry prominent notices stating that it is +released under this License and any conditions added under section +7. This requirement modifies the requirement in section 4 to +"keep intact all notices". - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. +c) You must license the entire work, as a whole, under this +License to anyone who comes into possession of a copy. This +License will therefore apply, along with any applicable section 7 +additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no +permission to license the work in any other way, but it does not +invalidate such permission if you have separately received it. - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. +d) If the work has interactive user interfaces, each must display +Appropriate Legal Notices; however, if the Program has interactive +interfaces that do not display Appropriate Legal Notices, your +work need not make them do so. - A compilation of a covered work with other separate and independent +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an @@ -242,59 +260,59 @@ beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - 6. Conveying Non-Source Forms. +6. Conveying Non-Source Forms. - You may convey a covered work in object code form under the terms +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. +a) Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by the +Corresponding Source fixed on a durable physical medium +customarily used for software interchange. - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. +b) Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by a +written offer, valid for at least three years and valid for as +long as you offer spare parts or customer support for that product +model, to give anyone who possesses the object code either (1) a +copy of the Corresponding Source for all the software in the +product that is covered by this License, on a durable physical +medium customarily used for software interchange, for a price no +more than your reasonable cost of physically performing this +conveying of source, or (2) access to copy the +Corresponding Source from a network server at no charge. - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. +c) Convey individual copies of the object code with a copy of the +written offer to provide the Corresponding Source. This +alternative is allowed only occasionally and noncommercially, and +only if you received the object code with such an offer, in accord +with subsection 6b. - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. +d) Convey the object code by offering access from a designated +place (gratis or for a charge), and offer equivalent access to the +Corresponding Source in the same way through the same place at no +further charge. You need not require recipients to copy the +Corresponding Source along with the object code. If the place to +copy the object code is a network server, the Corresponding Source +may be on a different server (operated by you or a third party) +that supports equivalent copying facilities, provided you maintain +clear directions next to the object code saying where to find the +Corresponding Source. Regardless of what server hosts the +Corresponding Source, you remain obligated to ensure that it is +available for as long as needed to satisfy these requirements. - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. +e) Convey the object code using peer-to-peer transmission, provided +you inform other peers where the object code and Corresponding +Source of the work are being offered to the general public at no +charge under subsection 6d. - A separable portion of the object code, whose source code is excluded +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - A "User Product" is either (1) a "consumer product", which means any +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, @@ -307,7 +325,7 @@ is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - "Installation Information" for a User Product means any methods, +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must @@ -315,7 +333,7 @@ suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - If you convey an object code work under this section in, or with, or +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a @@ -326,7 +344,7 @@ if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - The requirement to provide Installation Information does not include a +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a @@ -334,15 +352,15 @@ network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - Corresponding Source conveyed, and Installation Information provided, +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - 7. Additional Terms. +7. Additional Terms. - "Additional permissions" are terms that supplement the terms of this +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent @@ -351,41 +369,41 @@ apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - When you convey a copy of a covered work, you may at your option +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - Notwithstanding any other provision of this License, for material you +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or +a) Disclaiming warranty or limiting liability differently from the +terms of sections 15 and 16 of this License; or - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or +b) Requiring preservation of specified reasonable legal notices or +author attributions in that material or in the Appropriate Legal +Notices displayed by works containing it; or - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or +c) Prohibiting misrepresentation of the origin of that material, or +requiring that modified versions of such material be marked in +reasonable ways as different from the original version; or - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or +d) Limiting the use for publicity purposes of names of licensors or +authors of the material; or - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or +e) Declining to grant rights under trademark law for use of some +trade names, trademarks, or service marks; or - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. +f) Requiring indemnification of licensors and authors of that +material by anyone who conveys the material (or modified versions of +it) with contractual assumptions of liability to the recipient, for +any liability that these contractual assumptions directly impose on +those licensors and authors. - All other non-permissive additional terms are considered "further +All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further @@ -395,46 +413,46 @@ License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - If you add terms to a covered work in accord with this section, you +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - Additional terms, permissive or non-permissive, may be stated in the +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - 8. Termination. +8. Termination. - You may not propagate or modify a covered work except as expressly +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - However, if you cease all violation of this License, then your +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - Moreover, your license from a particular copyright holder is +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - Termination of your rights under this section does not terminate the +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - 9. Acceptance Not Required for Having Copies. +9. Acceptance Not Required for Having Copies. - You are not required to accept this License in order to receive or +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, @@ -443,14 +461,14 @@ modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - 10. Automatic Licensing of Downstream Recipients. +10. Automatic Licensing of Downstream Recipients. - Each time you convey a covered work, the recipient automatically +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - An "entity transaction" is a transaction transferring control of an +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that @@ -460,7 +478,7 @@ give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - You may not impose any further restrictions on the exercise of the +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation @@ -468,13 +486,13 @@ rights granted under this License, and you may not initiate litigation any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - 11. Patents. +11. Patents. - A "contributor" is a copyright holder who authorizes use under this +A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". - A contributor's "essential patent claims" are all patent claims +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, @@ -484,19 +502,19 @@ purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - Each contributor grants you a non-exclusive, worldwide, royalty-free +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - In the following three paragraphs, a "patent license" is any express +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - If you convey a covered work, knowingly relying on a patent license, +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, @@ -510,7 +528,7 @@ covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - If, pursuant to or in connection with a single transaction or +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify @@ -518,7 +536,7 @@ or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - A patent license is "discriminatory" if it does not include within +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered @@ -533,13 +551,13 @@ for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - Nothing in this License shall be construed as excluding or limiting +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - 12. No Surrender of Others' Freedom. +12. No Surrender of Others' Freedom. - If conditions are imposed on you (whether by court order, agreement or +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this @@ -549,9 +567,9 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. +13. Use with the GNU Affero General Public License. - Notwithstanding any other provision of this License, you have +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this @@ -560,14 +578,14 @@ but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - 14. Revised Versions of this License. +14. Revised Versions of this License. - The Free Software Foundation may publish revised and/or new versions of +The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - Each version is given a distinguishing version number. If the +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered @@ -576,19 +594,19 @@ Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - If the Program specifies that a proxy can decide which future +If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - Later license versions may give you additional or different +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - 15. Disclaimer of Warranty. +15. Disclaimer of Warranty. - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, @@ -597,9 +615,9 @@ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 16. Limitation of Liability. +16. Limitation of Liability. - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE @@ -609,64 +627,64 @@ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - 17. Interpretation of Sections 15 and 16. +17. Interpretation of Sections 15 and 16. - If the disclaimer of warranty and limitation of liability provided +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS - How to Apply These Terms to Your New Programs +How to Apply These Terms to Your New Programs - If you develop a new program, and you want it to be of the greatest +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. It is safest +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + +Copyright (C) - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . +You should have received a copy of the GNU General Public License +along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short +If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. + Copyright (C) +This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +This is free software, and you are welcome to redistribute it +under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". - You should also get your employer (if you work as a programmer) or school, +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . - The GNU General Public License does not permit incorporating your program +The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General diff --git a/templates/admin/deprecated/html-variation-price.php b/vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php similarity index 100% rename from templates/admin/deprecated/html-variation-price.php rename to vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-price.php diff --git a/templates/admin/deprecated/html-variation-synchronisation.php b/vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-synchronisation.php similarity index 100% rename from templates/admin/deprecated/html-variation-synchronisation.php rename to vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-synchronisation.php diff --git a/templates/admin/deprecated/order-shipping-html.php b/vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php similarity index 100% rename from templates/admin/deprecated/order-shipping-html.php rename to vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-shipping-html.php diff --git a/templates/admin/deprecated/order-tax-html.php b/vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-tax-html.php similarity index 100% rename from templates/admin/deprecated/order-tax-html.php rename to vendor/woocommerce/subscriptions-core/templates/admin/deprecated/order-tax-html.php diff --git a/templates/admin/html-admin-notice.php b/vendor/woocommerce/subscriptions-core/templates/admin/html-admin-notice.php similarity index 100% rename from templates/admin/html-admin-notice.php rename to vendor/woocommerce/subscriptions-core/templates/admin/html-admin-notice.php diff --git a/templates/admin/html-failed-scheduled-action-notice.php b/vendor/woocommerce/subscriptions-core/templates/admin/html-failed-scheduled-action-notice.php similarity index 100% rename from templates/admin/html-failed-scheduled-action-notice.php rename to vendor/woocommerce/subscriptions-core/templates/admin/html-failed-scheduled-action-notice.php diff --git a/templates/admin/html-variation-price.php b/vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php similarity index 100% rename from templates/admin/html-variation-price.php rename to vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php diff --git a/templates/admin/html-variation-synchronisation.php b/vendor/woocommerce/subscriptions-core/templates/admin/html-variation-synchronisation.php similarity index 100% rename from templates/admin/html-variation-synchronisation.php rename to vendor/woocommerce/subscriptions-core/templates/admin/html-variation-synchronisation.php diff --git a/templates/admin/status.php b/vendor/woocommerce/subscriptions-core/templates/admin/status.php similarity index 100% rename from templates/admin/status.php rename to vendor/woocommerce/subscriptions-core/templates/admin/status.php diff --git a/templates/cart/cart-recurring-shipping.php b/vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php similarity index 100% rename from templates/cart/cart-recurring-shipping.php rename to vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php diff --git a/templates/checkout/form-change-payment-method.php b/vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php similarity index 95% rename from templates/checkout/form-change-payment-method.php rename to vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php index 26aee96..18812e8 100644 --- a/templates/checkout/form-change-payment-method.php +++ b/vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php @@ -51,6 +51,7 @@ if ( ! defined( 'ABSPATH' ) ) { $pay_order_button_text = apply_filters( 'woocommerce_change_payment_button_text', $pay_order_button_text ); $customer_subscription_ids = WCS_Customer_Store::instance()->get_users_subscription_ids( $subscription->get_customer_id() ); + $payment_gateways_handler = WC_Subscriptions_Core_Plugin::instance()->get_gateways_handler_class(); if ( $available_gateways = WC()->payment_gateways->get_available_payment_gateways() ) : ?> @@ -84,7 +85,7 @@ if ( ! defined( 'ABSPATH' ) ) { - 1 && WC_Subscriptions_Payment_Gateways::one_gateway_supports( 'subscription_payment_method_change_admin' ) ) : ?> + 1 && $payment_gateways_handler::one_gateway_supports( 'subscription_payment_method_change_admin' ) ) : ?> tag, $2: closing tag diff --git a/vendor/woocommerce/subscriptions-core/templates/checkout/recurring-coupon-totals.php b/vendor/woocommerce/subscriptions-core/templates/checkout/recurring-coupon-totals.php new file mode 100644 index 0000000..c3223d8 --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/templates/checkout/recurring-coupon-totals.php @@ -0,0 +1,34 @@ +cart->get_coupons() as $code => $coupon ) { + foreach ( $recurring_carts as $recurring_cart_key => $recurring_cart ) { + foreach ( $recurring_cart->get_coupons() as $recurring_code => $recurring_coupon ) { + if ( $recurring_code !== $code ) { + continue; + } ?> + + + + + + + + + + $recurring_cart ) { + foreach ( $recurring_cart->get_fees() as $recurring_fee ) { ?> + + name ); ?> + + cart->get_taxes() as $tax_id => $tax_total ) { + foreach ( $recurring_carts as $recurring_cart_key => $recurring_cart ) { + foreach ( $recurring_cart->get_tax_totals() as $recurring_code => $recurring_tax ) { + if ( ! isset( $recurring_tax->tax_rate_id ) || $recurring_tax->tax_rate_id !== $tax_id ) { + continue; + } + + /** + * Allow third-parties to filter the tax displayed. + * + * @since 3.1.0 + * @param string The recurring cart's tax total price string for this tax code. + * @param WC_Cart $recurring_cart The recurring cart. + * @param string $recurring_code The tax code. + * @param object $recurring_tax The recurring tax data generated by @see WC_Cart::get_tax_totals() + */ + $tax_amount = wp_kses_post( apply_filters( 'wcs_recurring_cart_itemized_tax_totals_html', wcs_cart_price_string( $recurring_tax->formatted_amount, $recurring_cart ), $recurring_cart, $recurring_code, $recurring_tax ) ); + + // If the returned amount is empty, skip it. + if ( empty( $tax_amount ) ) { + continue; + } ?> + + + + + + label ); ?> + + + + + $recurring_cart ) { ?> + + + + + + + + + + $recurring_cart ) { ?> + + + + + + + + + $recurring_cart ) { + /** + * Allow third-parties to filter the tax displayed. + * + * @since 3.1.0 + * @param string The recurring cart's total tax price string. + * @param WC_Cart $recurring_cart The recurring cart. + */ + $tax_amount = wp_kses_post( apply_filters( 'wcs_recurring_cart_tax_totals_html', wcs_cart_price_string( $recurring_cart->get_taxes_total(), $recurring_cart ), $recurring_cart ) ); + + // Skip the tax if there's nothing to display. + if ( empty( $tax_amount ) ) { + continue; + } ?> + + + + + + countries->tax_or_vat() ); ?> + + + + + + + + + + + diff --git a/templates/checkout/subscription-receipt.php b/vendor/woocommerce/subscriptions-core/templates/checkout/subscription-receipt.php similarity index 100% rename from templates/checkout/subscription-receipt.php rename to vendor/woocommerce/subscriptions-core/templates/checkout/subscription-receipt.php diff --git a/templates/emails/admin-new-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php similarity index 100% rename from templates/emails/admin-new-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php diff --git a/templates/emails/admin-new-switch-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php similarity index 100% rename from templates/emails/admin-new-switch-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php diff --git a/templates/emails/admin-payment-retry.php b/vendor/woocommerce/subscriptions-core/templates/emails/admin-payment-retry.php similarity index 100% rename from templates/emails/admin-payment-retry.php rename to vendor/woocommerce/subscriptions-core/templates/emails/admin-payment-retry.php diff --git a/templates/emails/cancelled-subscription.php b/vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php similarity index 100% rename from templates/emails/cancelled-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php diff --git a/templates/emails/customer-completed-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php similarity index 100% rename from templates/emails/customer-completed-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php diff --git a/templates/emails/customer-completed-switch-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php similarity index 100% rename from templates/emails/customer-completed-switch-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php diff --git a/templates/emails/customer-on-hold-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php similarity index 100% rename from templates/emails/customer-on-hold-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php diff --git a/templates/emails/customer-payment-retry.php b/vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php similarity index 100% rename from templates/emails/customer-payment-retry.php rename to vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php diff --git a/templates/emails/customer-processing-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/customer-processing-renewal-order.php similarity index 100% rename from templates/emails/customer-processing-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/customer-processing-renewal-order.php diff --git a/templates/emails/customer-renewal-invoice.php b/vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php similarity index 100% rename from templates/emails/customer-renewal-invoice.php rename to vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php diff --git a/templates/emails/email-order-details.php b/vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php similarity index 100% rename from templates/emails/email-order-details.php rename to vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php diff --git a/templates/emails/expired-subscription.php b/vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php similarity index 100% rename from templates/emails/expired-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php diff --git a/templates/emails/on-hold-subscription.php b/vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php similarity index 100% rename from templates/emails/on-hold-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php diff --git a/templates/emails/plain/admin-new-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-renewal-order.php similarity index 100% rename from templates/emails/plain/admin-new-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-renewal-order.php diff --git a/templates/emails/plain/admin-new-switch-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-switch-order.php similarity index 100% rename from templates/emails/plain/admin-new-switch-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-switch-order.php diff --git a/templates/emails/plain/admin-payment-retry.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-payment-retry.php similarity index 100% rename from templates/emails/plain/admin-payment-retry.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-payment-retry.php diff --git a/templates/emails/plain/cancelled-subscription.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php similarity index 100% rename from templates/emails/plain/cancelled-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php diff --git a/templates/emails/plain/customer-completed-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-renewal-order.php similarity index 100% rename from templates/emails/plain/customer-completed-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-renewal-order.php diff --git a/templates/emails/plain/customer-completed-switch-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php similarity index 100% rename from templates/emails/plain/customer-completed-switch-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php diff --git a/templates/emails/plain/customer-on-hold-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-on-hold-renewal-order.php similarity index 100% rename from templates/emails/plain/customer-on-hold-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-on-hold-renewal-order.php diff --git a/templates/emails/plain/customer-payment-retry.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-payment-retry.php similarity index 100% rename from templates/emails/plain/customer-payment-retry.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-payment-retry.php diff --git a/templates/emails/plain/customer-processing-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-processing-renewal-order.php similarity index 100% rename from templates/emails/plain/customer-processing-renewal-order.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-processing-renewal-order.php diff --git a/templates/emails/plain/customer-renewal-invoice.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php similarity index 100% rename from templates/emails/plain/customer-renewal-invoice.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php diff --git a/templates/emails/plain/email-order-details.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/email-order-details.php similarity index 100% rename from templates/emails/plain/email-order-details.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/email-order-details.php diff --git a/templates/emails/plain/expired-subscription.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php similarity index 100% rename from templates/emails/plain/expired-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php diff --git a/templates/emails/plain/on-hold-subscription.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php similarity index 100% rename from templates/emails/plain/on-hold-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php diff --git a/templates/emails/plain/subscription-info.php b/vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php similarity index 98% rename from templates/emails/plain/subscription-info.php rename to vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php index 2204d5e..6b9dad9 100644 --- a/templates/emails/plain/subscription-info.php +++ b/vendor/woocommerce/subscriptions-core/templates/emails/plain/subscription-info.php @@ -48,8 +48,8 @@ if ( $has_automatic_renewal && ! $is_admin_email && $subscription->get_time( 'ne $my_account_url = wc_get_endpoint_url( 'subscriptions', '', wc_get_page_permalink( 'myaccount' ) ); } + // Translators: Placeholder is the My Account URL. echo wp_kses_post( sprintf( _n( - // Translators: Placeholder is the My Account URL. 'This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your my account page. %s', 'These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your my account page. %s', count( $subscriptions ), diff --git a/templates/emails/subscription-info.php b/vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php similarity index 97% rename from templates/emails/subscription-info.php rename to vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php index 59f65c4..1c30116 100644 --- a/templates/emails/subscription-info.php +++ b/vendor/woocommerce/subscriptions-core/templates/emails/subscription-info.php @@ -54,8 +54,8 @@ $is_parent_order = wcs_order_contains_subscription( $order, 'parent' ); $my_account_url = wc_get_endpoint_url( 'subscriptions', '', wc_get_page_permalink( 'myaccount' ) ); } + // Translators: Placeholders are opening and closing My Account link tags. printf( '%s', wp_kses_post( sprintf( _n( - // Translators: Placeholders are opening and closing My Account link tags. 'This subscription is set to renew automatically using your payment method on file. You can manage or cancel this subscription from your %smy account page%s.', 'These subscriptions are set to renew automatically using your payment method on file. You can manage or cancel your subscriptions from your %smy account page%s.', count( $subscriptions ), diff --git a/templates/html-modal.php b/vendor/woocommerce/subscriptions-core/templates/html-modal.php similarity index 100% rename from templates/html-modal.php rename to vendor/woocommerce/subscriptions-core/templates/html-modal.php diff --git a/templates/myaccount/my-subscriptions.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php similarity index 100% rename from templates/myaccount/my-subscriptions.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php diff --git a/templates/myaccount/related-orders.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php similarity index 100% rename from templates/myaccount/related-orders.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php diff --git a/templates/myaccount/related-subscriptions.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php similarity index 100% rename from templates/myaccount/related-subscriptions.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php diff --git a/templates/myaccount/subscription-details.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php similarity index 97% rename from templates/myaccount/subscription-details.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php index b6d0fc8..8cbbb8a 100644 --- a/templates/myaccount/subscription-details.php +++ b/vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-details.php @@ -50,7 +50,7 @@ if ( ! defined( 'ABSPATH' ) ) { $toggle_label = __( 'Enable auto renew', 'woocommerce-subscriptions' ); $toggle_classes[] = 'subscription-auto-renew-toggle--off'; - if ( WC_Subscriptions::is_duplicate_site() ) { + if ( WCS_Staging::is_duplicate_site() ) { $toggle_classes[] = 'subscription-auto-renew-toggle--disabled'; } } else { @@ -58,7 +58,7 @@ if ( ! defined( 'ABSPATH' ) ) { $toggle_classes[] = 'subscription-auto-renew-toggle--on'; }?> - +
    diff --git a/templates/myaccount/subscription-totals-table.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals-table.php similarity index 100% rename from templates/myaccount/subscription-totals-table.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals-table.php diff --git a/templates/myaccount/subscription-totals.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals.php similarity index 100% rename from templates/myaccount/subscription-totals.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals.php diff --git a/templates/myaccount/subscriptions.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/subscriptions.php similarity index 76% rename from templates/myaccount/subscriptions.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/subscriptions.php index 53c761a..4ec147a 100644 --- a/templates/myaccount/subscriptions.php +++ b/vendor/woocommerce/subscriptions-core/templates/myaccount/subscriptions.php @@ -11,4 +11,4 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } -WC_Subscriptions::get_my_subscriptions_template( $current_page ); +WCS_Template_Loader::get_my_subscriptions( $current_page ); diff --git a/templates/myaccount/view-subscription.php b/vendor/woocommerce/subscriptions-core/templates/myaccount/view-subscription.php similarity index 100% rename from templates/myaccount/view-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/myaccount/view-subscription.php diff --git a/templates/single-product/add-to-cart/subscription.php b/vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/subscription.php similarity index 100% rename from templates/single-product/add-to-cart/subscription.php rename to vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/subscription.php diff --git a/templates/single-product/add-to-cart/variable-subscription.php b/vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php similarity index 97% rename from templates/single-product/add-to-cart/variable-subscription.php rename to vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php index dda0d19..7fc8c36 100644 --- a/templates/single-product/add-to-cart/variable-subscription.php +++ b/vendor/woocommerce/subscriptions-core/templates/single-product/add-to-cart/variable-subscription.php @@ -54,7 +54,7 @@ do_action( 'woocommerce_before_add_to_cart_form' ); ?> /** * Post WC 3.4 the woocommerce_before_add_to_cart_button hook is triggered by the callback @see woocommerce_single_variation_add_to_cart_button() hooked onto woocommerce_single_variation. */ - if ( WC_Subscriptions::is_woocommerce_pre( '3.4' ) ) { + if ( wcs_is_woocommerce_pre( '3.4' ) ) { do_action( 'woocommerce_before_add_to_cart_button' ); } ?> @@ -86,7 +86,7 @@ do_action( 'woocommerce_before_add_to_cart_form' ); ?> /** * Post WC 3.4 the woocommerce_after_add_to_cart_button hook is triggered by the callback @see woocommerce_single_variation_add_to_cart_button() hooked onto woocommerce_single_variation. */ - if ( WC_Subscriptions::is_woocommerce_pre( '3.4' ) ) { + if ( wcs_is_woocommerce_pre( '3.4' ) ) { do_action( 'woocommerce_after_add_to_cart_button' ); } ?> diff --git a/wcs-functions.php b/vendor/woocommerce/subscriptions-core/wcs-functions.php similarity index 98% rename from wcs-functions.php rename to vendor/woocommerce/subscriptions-core/wcs-functions.php index d93f828..f49c8a4 100644 --- a/wcs-functions.php +++ b/vendor/woocommerce/subscriptions-core/wcs-functions.php @@ -2,10 +2,7 @@ /** * WooCommerce Subscriptions Functions * - * @author Prospress - * @category Core - * @package WooCommerce Subscriptions/Functions - * @version 2.0 + * @version 2.0 */ if ( ! defined( 'ABSPATH' ) ) { @@ -443,7 +440,7 @@ function wcs_get_subscriptions( $args ) { ); // if order_id is not a shop_order - if ( 0 !== $args['order_id'] && 'shop_order' !== get_post_type( $args['order_id'] ) ) { + if ( 0 !== $args['order_id'] && 'shop_order' !== WC_Data_Store::load( 'order' )->get_order_type( $args['order_id'] ) ) { return array(); } @@ -724,7 +721,7 @@ function wcs_is_view_subscription_page() { * @since 2.2.20 */ function wcs_get_image_asset_url( $file_name ) { - return plugins_url( "/assets/images/{$file_name}", WC_Subscriptions::$plugin_file ); + return WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( "assets/images/{$file_name}" ); } /** @@ -739,7 +736,7 @@ function wcs_subscription_search( $term ) { $subscription_ids = array(); - if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! wcs_is_woocommerce_pre( '3.0' ) ) { $data_store = WC_Data_Store::load( 'subscription' ); $subscription_ids = $data_store->search_subscriptions( str_replace( 'Order #', '', wc_clean( $term ) ) ); @@ -853,7 +850,7 @@ function wcs_set_payment_meta( $subscription, $payment_meta ) { } /** - * Get total quantity of a product on a subscription or order, even across multiple line items. + * Get total quantity of a product on a subscription or order, even across multiple line items. So we can determine if product has stock available. * * @since 2.6.0 * @@ -880,7 +877,13 @@ function wcs_get_total_line_item_product_quantity( $order, $product, $product_ma $product_id = $product->get_id(); // The variation ID for variations or product ID. break; default: - $line_item_product_id = $line_item->get_product()->get_stock_managed_by_id(); + $line_item_product = $line_item->get_product(); + if ( false === $line_item_product ) { + // Skip processing here if line item product doesn't exist. + // NB: Product not found generates a notice later in the flow in \WCS_Cart_Renewal::setup_cart + continue 2; + } + $line_item_product_id = $line_item_product->get_stock_managed_by_id(); $product_id = $product->get_stock_managed_by_id(); break; } diff --git a/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php b/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php new file mode 100644 index 0000000..3c537fd --- /dev/null +++ b/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php @@ -0,0 +1,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/woo-includes/woo-functions.php b/woo-includes/woo-functions.php index f92bdb1..2529601 100644 --- a/woo-includes/woo-functions.php +++ b/woo-includes/woo-functions.php @@ -58,38 +58,6 @@ if ( ! class_exists( 'WooThemes_Updater' ) && ! function_exists( 'woothemes_upda add_filter( 'plugins_api', 'woothemes_updater_install', 10, 3 ); } -/** - * WooUpdater Installation Prompts - */ -if ( ! class_exists( 'WooThemes_Updater' ) && ! function_exists( 'woothemes_updater_notice' ) ) { - - /** - * Display a notice if the "WooThemes Updater" plugin hasn't been installed. - * @return void - */ - function woothemes_updater_notice() { - $active_plugins = apply_filters( 'active_plugins', get_option('active_plugins' ) ); - if ( in_array( 'woothemes-updater/woothemes-updater.php', $active_plugins ) ) return; - - $slug = 'woothemes-updater'; - $install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $slug ), 'install-plugin_' . $slug ); - $activate_url = 'plugins.php?action=activate&plugin=' . urlencode( 'woothemes-updater/woothemes-updater.php' ) . '&plugin_status=all&paged=1&s&_wpnonce=' . urlencode( wp_create_nonce( 'activate-plugin_woothemes-updater/woothemes-updater.php' ) ); - - $message = 'Install the WooThemes Helper plugin to get updates for your WooThemes plugins.'; - $is_downloaded = false; - $plugins = array_keys( get_plugins() ); - foreach ( $plugins as $plugin ) { - if ( strpos( $plugin, 'woothemes-updater.php' ) !== false ) { - $is_downloaded = true; - $message = 'Activate the WooThemes Helper plugin to get updates for your WooThemes plugins.'; - } - } - echo '

    ' . $message . '

    ' . "\n"; - } - - add_action( 'admin_notices', 'woothemes_updater_notice' ); -} - /** * Prevent conflicts with older versions */ diff --git a/woocommerce-subscriptions.php b/woocommerce-subscriptions.php index 31f5ef3..4aa84ac 100644 --- a/woocommerce-subscriptions.php +++ b/woocommerce-subscriptions.php @@ -5,10 +5,10 @@ * Description: Sell products and services with recurring payments in your WooCommerce Store. * Author: WooCommerce * Author URI: https://woocommerce.com/ - * Version: 3.0.9 + * Version: 4.6.0 * - * WC requires at least: 3.0.9 - * WC tested up to: 4.5 + * WC requires at least: 4.4 + * WC tested up to: 6.5.0 * Woo: 27147:6115e6d7e297b623a169fdcf5728b224 * * Copyright 2019 WooCommerce @@ -35,14 +35,9 @@ * Required functions */ if ( ! function_exists( 'woothemes_queue_update' ) || ! function_exists( 'is_woocommerce_active' ) ) { - require_once( dirname( __FILE__ ) . '/woo-includes/woo-functions.php' ); + require_once dirname( __FILE__ ) . '/woo-includes/woo-functions.php'; } -/** - * Plugin updates - */ -woothemes_queue_update( plugin_basename( __FILE__ ), '6115e6d7e297b623a169fdcf5728b224', '27147' ); - /** * Check if WooCommerce is active and at the required minimum version, and if it isn't, disable Subscriptions. * @@ -53,58 +48,25 @@ if ( ! is_woocommerce_active() || version_compare( get_option( 'woocommerce_db_v return; } -define( 'WCS_INIT_TIMESTAMP', gmdate( 'U' ) ); +/** + * Declare plugin incompatibility with WooCommerce HPOS. + * + * @since 4.6.0 + */ +add_action( + 'before_woocommerce_init', + function() { + if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) { + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, false ); + } + } +); -// Manually load functions files. -require_once( dirname( __FILE__ ) . '/wcs-functions.php' ); -require_once( dirname( __FILE__ ) . '/includes/gateways/paypal/includes/wcs-paypal-functions.php' ); +// Subscribe to automated translations. +add_action( 'woocommerce_translations_updates_for_woocommerce-subscriptions', '__return_true' ); // Load and set up the Autoloader -require_once( dirname( __FILE__ ) . '/includes/class-wcs-autoloader.php' ); -$wcs_autoloader = new WCS_Autoloader( dirname( __FILE__ ) ); -$wcs_autoloader->register(); - -// Load libraries manually. -require_once( dirname( __FILE__ ) . '/includes/libraries/action-scheduler/action-scheduler.php' ); - -// Initialize our classes. -WC_Subscriptions_Coupon::init(); -WC_Subscriptions_Product::init(); -WC_Subscriptions_Admin::init(); -WC_Subscriptions_Manager::init(); -WC_Subscriptions_Cart::init(); -WC_Subscriptions_Cart_Validator::init(); -WC_Subscriptions_Order::init(); -WC_Subscriptions_Renewal_Order::init(); -WC_Subscriptions_Checkout::init(); -WC_Subscriptions_Email::init(); -WC_Subscriptions_Addresses::init(); -WC_Subscriptions_Change_Payment_Gateway::init(); -WC_Subscriptions_Payment_Gateways::init(); -WCS_PayPal_Standard_Change_Payment_Method::init(); -WC_Subscriptions_Switcher::init(); -WC_Subscriptions_Tracker::init(); -WCS_Upgrade_Logger::init(); -new WCS_Cart_Renewal(); -new WCS_Cart_Resubscribe(); -new WCS_Cart_Initial_Payment(); -WCS_Download_Handler::init(); -WCS_Retry_Manager::init(); -new WCS_Cart_Switch(); -WCS_Limiter::init(); -WCS_Admin_System_Status::init(); -WCS_Upgrade_Notice_Manager::init(); -WCS_Staging::init(); -WCS_Permalink_Manager::init(); -WCS_Custom_Order_Item_Manager::init(); -WCS_Early_Renewal_Modal_Handler::init(); -WCS_Dependent_Hook_Manager::init(); - -// Some classes run init on a particular hook. -add_action( 'init', array( 'WC_Subscriptions_Synchroniser', 'init' ) ); -add_action( 'after_setup_theme', array( 'WC_Subscriptions_Upgrader', 'init' ), 11 ); -add_action( 'init', array( 'WC_PayPal_Standard_Subscriptions', 'init' ), 11 ); -add_action( 'init', array( 'WCS_WC_Admin_Manager', 'init' ), 11 ); +$wcs_autoloader = wcs_init_autoloader(); /** * The main subscriptions class. @@ -113,19 +75,20 @@ add_action( 'init', array( 'WCS_WC_Admin_Manager', 'init' ), 11 ); */ class WC_Subscriptions { + /** @var string */ public static $name = 'subscription'; + /** @var string */ public static $activation_transient = 'woocommerce_subscriptions_activated'; + /** @var string */ public static $plugin_file = __FILE__; - public static $version = '3.0.9'; + /** @var string */ + public static $version = '4.6.0'; - public static $wc_minimum_supported_version = '3.0'; - - private static $total_subscription_count = null; - - private static $scheduler; + /** @var string */ + public static $wc_minimum_supported_version = '4.4'; /** @var WCS_Cache_Manager */ public static $cache; @@ -141,560 +104,11 @@ class WC_Subscriptions { * @param WCS_Autoloader $autoloader Autoloader instance. */ public static function init( $autoloader = null ) { - self::$autoloader = $autoloader ? $autoloader : new WCS_Autoloader( dirname( __FILE__ ) ); - - // Register our custom subscription order type after WC_Post_types::register_post_types() - add_action( 'init', __CLASS__ . '::register_order_types', 6 ); - - add_filter( 'woocommerce_data_stores', __CLASS__ . '::add_data_stores', 10, 1 ); - - // Register our custom subscription order statuses before WC_Post_types::register_post_status() - add_action( 'init', __CLASS__ . '::register_post_status', 9 ); - - add_action( 'init', __CLASS__ . '::maybe_activate_woocommerce_subscriptions' ); - - register_deactivation_hook( __FILE__, __CLASS__ . '::deactivate_woocommerce_subscriptions' ); - - // Override the WC default "Add to cart" text to "Sign up now" (in various places/templates) - add_filter( 'woocommerce_order_button_text', __CLASS__ . '::order_button_text' ); - add_action( 'woocommerce_subscription_add_to_cart', __CLASS__ . '::subscription_add_to_cart', 30 ); - add_action( 'woocommerce_variable-subscription_add_to_cart', __CLASS__ . '::variable_subscription_add_to_cart', 30 ); - add_action( 'wcopc_subscription_add_to_cart', __CLASS__ . '::wcopc_subscription_add_to_cart' ); // One Page Checkout compatibility - - // Enqueue front-end styles, run after Storefront because it sets the styles to be empty - add_filter( 'woocommerce_enqueue_styles', __CLASS__ . '::enqueue_styles', 100, 1 ); - - // Load translation files - add_action( 'init', __CLASS__ . '::load_plugin_textdomain', 3 ); - - // Load frontend scripts - add_action( 'wp_enqueue_scripts', __CLASS__ . '::enqueue_frontend_scripts', 3 ); - - // Load dependent files - add_action( 'plugins_loaded', __CLASS__ . '::load_dependant_classes' ); - - // Attach hooks which depend on WooCommerce constants - add_action( 'plugins_loaded', array( __CLASS__, 'attach_dependant_hooks' ) ); - - // Make sure the related order data store instance is loaded and initialised so that cache management will function - add_action( 'plugins_loaded', 'WCS_Related_Order_Store::instance' ); - - // Make sure the related order data store instance is loaded and initialised so that cache management will function - add_action( 'plugins_loaded', 'WCS_Customer_Store::instance' ); - - // Staging site or site migration notice - add_action( 'admin_notices', __CLASS__ . '::woocommerce_site_change_notice' ); - - // Add the "Settings | Documentation" links on the Plugins administration screen - add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), __CLASS__ . '::action_links' ); - - add_filter( 'action_scheduler_queue_runner_batch_size', __CLASS__ . '::action_scheduler_multisite_batch_size' ); - - add_action( 'in_plugin_update_message-' . plugin_basename( __FILE__ ), __CLASS__ . '::update_notice', 10, 2 ); - - // get details of orders of a customer - add_action( 'wp_ajax_wcs_get_customer_orders', __CLASS__ . '::get_customer_orders' ); - - self::$cache = WCS_Cache_Manager::get_instance(); - - $scheduler_class = apply_filters( 'woocommerce_subscriptions_scheduler', 'WCS_Action_Scheduler' ); - - self::$scheduler = new $scheduler_class(); + $plugin = new WC_Subscriptions_Plugin( $autoloader ); + self::$cache = $plugin->cache; + self::$autoloader = $plugin->get_autoloader(); } - /** - * Get customer's order details via ajax. - */ - public static function get_customer_orders() { - check_ajax_referer( 'get-customer-orders', 'security' ); - - if ( ! current_user_can( 'edit_shop_orders' ) ) { - wp_die( -1 ); - } - - $user_id = absint( $_POST['user_id'] ); - - $orders = wc_get_orders( - array( - 'customer' => $user_id, - 'post_type' => 'shop_order', - 'posts_per_page' => '-1', - ) - ); - - $customer_orders = array(); - foreach ( $orders as $order ) { - $customer_orders[ wcs_get_objects_property( $order, 'id' ) ] = $order->get_order_number(); - } - - wp_send_json( $customer_orders ); - } - - /** - * Register data stores for WooCommerce 3.0+ - * - * @since 2.2.0 - */ - public static function add_data_stores( $data_stores ) { - // Our custom data stores. - $data_stores['subscription'] = 'WCS_Subscription_Data_Store_CPT'; - $data_stores['product-variable-subscription'] = 'WCS_Product_Variable_Data_Store_CPT'; - - // Use WC core data stores for our products. - $data_stores['product-subscription_variation'] = 'WC_Product_Variation_Data_Store_CPT'; - $data_stores['order-item-line_item_pending_switch'] = 'WC_Order_Item_Product_Data_Store'; - - return $data_stores; - } - - /** - * Register core post types - * - * @since 2.0 - */ - public static function register_order_types() { - - wc_register_order_type( - 'shop_subscription', - apply_filters( 'woocommerce_register_post_type_subscription', - array( - // register_post_type() params - 'labels' => array( - 'name' => __( 'Subscriptions', 'woocommerce-subscriptions' ), - 'singular_name' => __( 'Subscription', 'woocommerce-subscriptions' ), - 'add_new' => _x( 'Add Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), - 'add_new_item' => _x( 'Add New Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), - 'edit' => _x( 'Edit', 'custom post type setting', 'woocommerce-subscriptions' ), - 'edit_item' => _x( 'Edit Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), - 'new_item' => _x( 'New Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), - 'view' => _x( 'View Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), - 'view_item' => _x( 'View Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), - 'search_items' => __( 'Search Subscriptions', 'woocommerce-subscriptions' ), - 'not_found' => self::get_not_found_text(), - 'not_found_in_trash' => _x( 'No Subscriptions found in trash', 'custom post type setting', 'woocommerce-subscriptions' ), - 'parent' => _x( 'Parent Subscriptions', 'custom post type setting', 'woocommerce-subscriptions' ), - 'menu_name' => __( 'Subscriptions', 'woocommerce-subscriptions' ), - ), - 'description' => __( 'This is where subscriptions are stored.', 'woocommerce-subscriptions' ), - 'public' => false, - 'show_ui' => true, - 'capability_type' => 'shop_order', - 'map_meta_cap' => true, - 'publicly_queryable' => false, - 'exclude_from_search' => true, - 'show_in_menu' => current_user_can( 'manage_woocommerce' ) ? 'woocommerce' : true, - 'hierarchical' => false, - 'show_in_nav_menus' => false, - 'rewrite' => false, - 'query_var' => false, - 'supports' => array( 'title', 'comments', 'custom-fields' ), - 'has_archive' => false, - - // wc_register_order_type() params - 'exclude_from_orders_screen' => true, - 'add_order_meta_boxes' => true, - 'exclude_from_order_count' => true, - 'exclude_from_order_views' => true, - 'exclude_from_order_webhooks' => true, - 'exclude_from_order_reports' => true, - 'exclude_from_order_sales_reports' => true, - 'class_name' => self::is_woocommerce_pre( '3.0' ) ? 'WC_Subscription_Legacy' : 'WC_Subscription', - ) - ) - ); - } - - /** - * Method that returns the not found text. If the user has created at least one subscription, the standard message - * will appear. If that's empty, the long, explanatory one will appear in the table. - * - * Filters: - * - woocommerce_subscriptions_not_empty: gets passed the boolean option value. 'true' means the subscriptions - * list is not empty, the user is familiar with how it works, and standard message appears. - * - woocommerce_subscriptions_not_found_label: gets the original message for other plugins to modify, in case - * they want to add more links, or modify any of the messages. - * @since 2.0 - * - * @return string what appears in the list table of the subscriptions - */ - private static function get_not_found_text() { - $subscriptions_exist = self::$cache->cache_and_get( 'wcs_do_subscriptions_exist', 'wcs_do_subscriptions_exist' ); - if ( true === apply_filters( 'woocommerce_subscriptions_not_empty', $subscriptions_exist ) ) { - $not_found_text = __( 'No Subscriptions found', 'woocommerce-subscriptions' ); - } else { - $not_found_text = '

    ' . __( 'Subscriptions will appear here for you to view and manage once purchased by a customer.', 'woocommerce-subscriptions' ) . '

    '; - // translators: placeholders are opening and closing link tags - $not_found_text .= '

    ' . sprintf( __( '%1$sLearn more about managing subscriptions »%2$s', 'woocommerce-subscriptions' ), '', '' ) . '

    '; - // translators: placeholders are opening and closing link tags - $not_found_text .= '

    ' . sprintf( __( '%1$sAdd a subscription product »%2$s', 'woocommerce-subscriptions' ), '', '' ) . '

    '; - } - - return apply_filters( 'woocommerce_subscriptions_not_found_label', $not_found_text ); - } - - /** - * Register our custom post statuses, used for order/subscription status - */ - public static function register_post_status() { - - $subscription_statuses = wcs_get_subscription_statuses(); - - $registered_statuses = apply_filters( 'woocommerce_subscriptions_registered_statuses', array( - // translators: placeholder is a post count. - 'wc-active' => _nx_noop( 'Active (%s)', 'Active (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), - // translators: placeholder is a post count. - 'wc-switched' => _nx_noop( 'Switched (%s)', 'Switched (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), - // translators: placeholder is a post count. - 'wc-expired' => _nx_noop( 'Expired (%s)', 'Expired (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), - // translators: placeholder is a post count. - 'wc-pending-cancel' => _nx_noop( 'Pending Cancellation (%s)', 'Pending Cancellation (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), - ) ); - - if ( is_array( $subscription_statuses ) && is_array( $registered_statuses ) ) { - - foreach ( $registered_statuses as $status => $label_count ) { - - register_post_status( $status, array( - 'label' => $subscription_statuses[ $status ], // use same label/translations as wcs_get_subscription_statuses() - 'public' => false, - 'exclude_from_search' => false, - 'show_in_admin_all_list' => true, - 'show_in_admin_status_list' => true, - 'label_count' => $label_count, - ) ); - } - } - } - - /** - * Enqueues scripts for frontend - * - * @since 2.3 - */ - public static function enqueue_frontend_scripts() { - $dependencies = array( 'jquery' ); - - if ( is_cart() || is_checkout() ) { - wp_enqueue_script( 'wcs-cart', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/frontend/wcs-cart.js', $dependencies, WC_Subscriptions::$version, true ); - } elseif ( is_product() ) { - wp_enqueue_script( 'wcs-single-product', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/frontend/single-product.js', $dependencies, WC_Subscriptions::$version, true ); - } elseif ( wcs_is_view_subscription_page() ) { - global $wp; - $subscription = wcs_get_subscription( $wp->query_vars['view-subscription'] ); - - if ( $subscription && current_user_can( 'view_order', $subscription->get_id() ) ) { - $dependencies[] = 'jquery-blockui'; - $script_params = array( - 'ajax_url' => esc_url( WC()->ajax_url() ), - 'subscription_id' => $subscription->get_id(), - 'add_payment_method_msg' => __( 'To enable automatic renewals for this subscription, you will first need to add a payment method.', 'woocommerce-subscriptions' ) . "\n\n" . __( 'Would you like to add a payment method now?', 'woocommerce-subscriptions' ), - 'auto_renew_nonce' => WCS_My_Account_Auto_Renew_Toggle::can_user_toggle_auto_renewal( $subscription ) ? wp_create_nonce( "toggle-auto-renew-{$subscription->get_id()}" ) : false, - 'add_payment_method_url' => esc_url( $subscription->get_change_payment_method_url() ), - 'has_payment_gateway' => $subscription->has_payment_gateway() && wc_get_payment_gateway_by_order( $subscription )->supports( 'subscriptions' ), - ); - wp_enqueue_script( 'wcs-view-subscription', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/frontend/view-subscription.js', $dependencies, WC_Subscriptions::$version, true ); - wp_localize_script( 'wcs-view-subscription', 'WCSViewSubscription', apply_filters( 'woocommerce_subscriptions_frontend_view_subscription_script_parameters', $script_params ) ); - } - } - } - - /** - * Enqueues stylesheet for the My Subscriptions table on the My Account page. - * - * @since 1.5 - */ - public static function enqueue_styles( $styles ) { - - if ( is_checkout() || is_cart() ) { - $styles['wcs-checkout'] = array( - 'src' => str_replace( array( 'http:', 'https:' ), '', plugin_dir_url( __FILE__ ) ) . 'assets/css/checkout.css', - 'deps' => 'wc-checkout', - 'version' => WC_VERSION, - 'media' => 'all', - ); - } elseif ( is_account_page() ) { - $styles['wcs-view-subscription'] = array( - 'src' => str_replace( array( 'http:', 'https:' ), '', plugin_dir_url( __FILE__ ) ) . 'assets/css/view-subscription.css', - 'deps' => 'woocommerce-smallscreen', - 'version' => self::$version, - 'media' => 'all', - ); - } - - return $styles; - } - - /** - * Loads the my-subscriptions.php template on the My Account page. - * - * @since 1.0 - * @param int $current_page - */ - public static function get_my_subscriptions_template( $current_page = 1 ) { - - $all_subscriptions = wcs_get_users_subscriptions(); - - $current_page = empty( $current_page ) ? 1 : absint( $current_page ); - $posts_per_page = get_option( 'posts_per_page' ); - - $max_num_pages = ceil( count( $all_subscriptions ) / $posts_per_page ); - - $subscriptions = array_slice( $all_subscriptions, ( $current_page - 1 ) * $posts_per_page, $posts_per_page ); - - wc_get_template( - 'myaccount/my-subscriptions.php', - array( - 'subscriptions' => $subscriptions, - 'current_page' => $current_page, - 'max_num_pages' => $max_num_pages, - 'paginate' => true, - ), - '', - plugin_dir_path( __FILE__ ) . 'templates/' - ); - } - - /** - * Output a redirect URL when an item is added to the cart when a subscription was already in the cart. - * - * @since 1.0 - */ - public static function redirect_ajax_add_to_cart( $fragments ) { - - $fragments['error'] = true; - $fragments['product_url'] = wc_get_cart_url(); - - # Force error on add_to_cart() to redirect - add_filter( 'woocommerce_add_to_cart_validation', '__return_false', 10 ); - add_filter( 'woocommerce_cart_redirect_after_error', __CLASS__ . '::redirect_to_cart', 10, 2 ); - do_action( 'wc_ajax_add_to_cart' ); - - return $fragments; - } - - /** - * Return a url for cart redirect. - * - * @since 2.3.0 - */ - public static function redirect_to_cart( $permalink, $product_id ) { - - return wc_get_cart_url(); - } - - /** - * When a subscription is added to the cart, remove other products/subscriptions to - * work with PayPal Standard, which only accept one subscription per checkout. - * - * If multiple purchase flag is set, allow them to be added at the same time. - * - * @deprecated 2.6.0 - * @since 1.0 - */ - public static function maybe_empty_cart( $valid, $product_id, $quantity, $variation_id = '', $variations = array() ) { - wcs_deprecated_function( __METHOD__, '2.6.0', 'WC_Subscriptions_Cart_Validator::maybe_empty_cart()' ); - - $is_subscription = WC_Subscriptions_Product::is_subscription( $product_id ); - $cart_contains_subscription = WC_Subscriptions_Cart::cart_contains_subscription(); - $multiple_subscriptions_possible = WC_Subscriptions_Payment_Gateways::one_gateway_supports( 'multiple_subscriptions' ); - $manual_renewals_enabled = ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ) ); - $canonical_product_id = ! empty( $variation_id ) ? $variation_id : $product_id; - - if ( $is_subscription && 'yes' != get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { - - // Generate a cart item key from variation and cart item data - which may be added by other plugins - $cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', array(), $product_id, $variation_id, $quantity ); - $cart_item_id = WC()->cart->generate_cart_id( $product_id, $variation_id, $variations, $cart_item_data ); - $product = wc_get_product( $product_id ); - - // If the product is sold individually or if the cart doesn't already contain this product, empty the cart. - if ( ( $product && $product->is_sold_individually() ) || ! WC()->cart->find_product_in_cart( $cart_item_id ) ) { - $coupons = WC()->cart->get_applied_coupons(); - WC()->cart->empty_cart(); - WC()->cart->set_applied_coupons( $coupons ); - } - } elseif ( $is_subscription && wcs_cart_contains_renewal() && ! $multiple_subscriptions_possible && ! $manual_renewals_enabled ) { - - WC_Subscriptions_Cart::remove_subscriptions_from_cart(); - - wc_add_notice( __( 'A subscription renewal has been removed from your cart. Multiple subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); - - } elseif ( $is_subscription && $cart_contains_subscription && ! $multiple_subscriptions_possible && ! $manual_renewals_enabled && ! WC_Subscriptions_Cart::cart_contains_product( $canonical_product_id ) ) { - - WC_Subscriptions_Cart::remove_subscriptions_from_cart(); - - wc_add_notice( __( 'A subscription has been removed from your cart. Due to payment gateway restrictions, different subscription products can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); - - } elseif ( $cart_contains_subscription && 'yes' != get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { - - WC_Subscriptions_Cart::remove_subscriptions_from_cart(); - - wc_add_notice( __( 'A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); - - // Redirect to cart page to remove subscription & notify shopper - if ( self::is_woocommerce_pre( '3.0.8' ) ) { - add_filter( 'add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart' ); - } else { - add_filter( 'woocommerce_add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart' ); - } - } - - return WC_Subscriptions_Cart_Validator::maybe_empty_cart( $valid, $product_id, $quantity, $variation_id, $variations ); - } - - /** - * Removes all subscription products from the shopping cart. - * - * @deprecated 2.6.0 - * @since 1.0 - */ - public static function remove_subscriptions_from_cart() { - wcs_deprecated_function( __METHOD__, '2.6.0', 'WC_Subscriptions_Cart::remove_subscriptions_from_cart()' ); - - WC_Subscriptions_Cart::remove_subscriptions_from_cart(); - } - - /** - * For a smoother sign up process, tell WooCommerce to redirect the shopper immediately to - * the checkout page after she clicks the "Sign up now" button - * - * Only enabled if multiple checkout is not enabled. - * - * @param string $url The cart redirect $url WooCommerce determined. - * @since 1.0 - */ - public static function add_to_cart_redirect( $url ) { - - // If product is of the subscription type - if ( isset( $_REQUEST['add-to-cart'] ) && is_numeric( $_REQUEST['add-to-cart'] ) && WC_Subscriptions_Product::is_subscription( (int) $_REQUEST['add-to-cart'] ) ) { - - // Redirect to checkout if mixed checkout is disabled - if ( 'yes' != get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { - - $quantity = isset( $_REQUEST['quantity'] ) ? $_REQUEST['quantity'] : 1; - $product_id = $_REQUEST['add-to-cart']; - - $add_to_cart_notice = wc_add_to_cart_message( array( $product_id => $quantity ), true, true ); - - if ( wc_has_notice( $add_to_cart_notice ) ) { - $notices = wc_get_notices(); - $add_to_cart_notice_index = array_search( $add_to_cart_notice, $notices['success'] ); - - unset( $notices['success'][ $add_to_cart_notice_index ] ); - wc_set_notices( $notices ); - } - - $url = wc_get_checkout_url(); - } - } - - return $url; - } - - /** - * Override the WooCommerce "Place order" text with "Sign up now" - * - * @since 1.0 - */ - public static function order_button_text( $button_text ) { - global $product; - - if ( WC_Subscriptions_Cart::cart_contains_subscription() ) { - $button_text = get_option( WC_Subscriptions_Admin::$option_prefix . '_order_button_text', __( 'Sign up now', 'woocommerce-subscriptions' ) ); - } - - return $button_text; - } - - /** - * Load the subscription add_to_cart template. - * - * Use the same cart template for subscription as that which is used for simple products. Reduce code duplication - * and is made possible by the friendly actions & filters found through WC. - * - * Not using a custom template both prevents code duplication and helps future proof this extension from core changes. - * - * @since 1.0 - */ - public static function subscription_add_to_cart() { - wc_get_template( 'single-product/add-to-cart/subscription.php', array(), '', plugin_dir_path( __FILE__ ) . 'templates/' ); - } - - /** - * Load the variable subscription add_to_cart template - * - * Use a very similar cart template as that of a variable product with added functionality. - * - * @since 2.0.9 - */ - public static function variable_subscription_add_to_cart() { - global $product; - - // Enqueue variation scripts - wp_enqueue_script( 'wc-add-to-cart-variation' ); - - // Get Available variations? - $get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product ); - - // Load the template - wc_get_template( 'single-product/add-to-cart/variable-subscription.php', array( - 'available_variations' => $get_variations ? $product->get_available_variations() : false, - 'attributes' => $product->get_variation_attributes(), - 'selected_attributes' => $product->get_default_attributes(), - ), '', plugin_dir_path( __FILE__ ) . 'templates/' ); - } - - /** - * Compatibility with WooCommerce On One Page Checkout. - * - * Use OPC's simple add to cart template for simple subscription products (to ensure data attributes required by OPC are added). - * - * Variable subscription products will be handled automatically because they identify as "variable" in response to is_type() method calls, - * which OPC uses. - * - * @since 1.5.16 - */ - public static function wcopc_subscription_add_to_cart() { - global $product; - wc_get_template( 'checkout/add-to-cart/simple.php', array( 'product' => $product ), '', PP_One_Page_Checkout::$template_path ); - } - - /** - * Takes a number and returns the number with its relevant suffix appended, eg. for 2, the function returns 2nd - * - * @since 1.0 - */ - public static function append_numeral_suffix( $number ) { - - // Handle teens: if the tens digit of a number is 1, then write "th" after the number. For example: 11th, 13th, 19th, 112th, 9311th. http://en.wikipedia.org/wiki/English_numerals - if ( strlen( $number ) > 1 && 1 == substr( $number, -2, 1 ) ) { - // translators: placeholder is a number, this is for the teens - $number_string = sprintf( __( '%sth', 'woocommerce-subscriptions' ), $number ); - } else { // Append relevant suffix - switch ( substr( $number, -1 ) ) { - case 1: - // translators: placeholder is a number, numbers ending in 1 - $number_string = sprintf( __( '%sst', 'woocommerce-subscriptions' ), $number ); - break; - case 2: - // translators: placeholder is a number, numbers ending in 2 - $number_string = sprintf( __( '%snd', 'woocommerce-subscriptions' ), $number ); - break; - case 3: - // translators: placeholder is a number, numbers ending in 3 - $number_string = sprintf( __( '%srd', 'woocommerce-subscriptions' ), $number ); - break; - default: - // translators: placeholder is a number, numbers ending in 4-9, 0 - $number_string = sprintf( __( '%sth', 'woocommerce-subscriptions' ), $number ); - break; - } - } - - return apply_filters( 'woocommerce_numeral_suffix', $number_string, $number ); - } - - /* * Plugin House Keeping */ @@ -728,680 +142,90 @@ class WC_Subscriptions { } if ( $admin_notice_content ) { - require_once( dirname( __FILE__ ) . '/includes/admin/class-wcs-admin-notice.php' ); - $notice = new WCS_Admin_Notice( 'error' ); - $notice->set_simple_content( $admin_notice_content ); - $notice->display(); + echo '
    '; + echo '

    ' . wp_kses_post( $admin_notice_content ) . '

    '; + echo '
    '; } } } - /** - * Checks on each admin page load if Subscriptions plugin is activated. - * - * Apparently the official WP API is "lame" and it's far better to use an upgrade routine fired on admin_init: http://core.trac.wordpress.org/ticket/14170 - * - * @since 1.1 - */ - public static function maybe_activate_woocommerce_subscriptions() { - $is_active = get_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', false ); - - if ( false == $is_active ) { - - // Add the "Subscriptions" product type - if ( ! get_term_by( 'slug', self::$name, 'product_type' ) ) { - wp_insert_term( self::$name, 'product_type' ); - } - - // Maybe add the "Variable Subscriptions" product type - if ( ! get_term_by( 'slug', 'variable-subscription', 'product_type' ) ) { - wp_insert_term( __( 'Variable Subscription', 'woocommerce-subscriptions' ), 'product_type' ); - } - - // If no Subscription settings exist, its the first activation, so add defaults - if ( get_option( WC_Subscriptions_Admin::$option_prefix . '_cancelled_role', false ) == false ) { - WC_Subscriptions_Admin::add_default_settings(); - } - - // if this is the first time activating WooCommerce Subscription we want to enable PayPal debugging by default. - if ( '0' == get_option( WC_Subscriptions_Admin::$option_prefix . '_previous_version', '0' ) && false == get_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', false ) ) { - $paypal_settings = get_option( 'woocommerce_paypal_settings' ); - $paypal_settings['debug'] = 'yes'; - update_option( 'woocommerce_paypal_settings', $paypal_settings ); - update_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', 'true' ); - } - - update_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', true ); - - set_transient( self::$activation_transient, true, 60 * 60 ); - - flush_rewrite_rules(); - - do_action( 'woocommerce_subscriptions_activated' ); - } - - } - - /** - * Called when the plugin is deactivated. Deletes the subscription product type and fires an action. - * - * @since 1.0 - */ - public static function deactivate_woocommerce_subscriptions() { - - delete_option( WC_Subscriptions_Admin::$option_prefix . '_is_active' ); - - flush_rewrite_rules(); - - do_action( 'woocommerce_subscriptions_deactivated' ); - } - - /** - * Called on plugins_loaded to load any translation files. - * - * @since 1.1 - */ - public static function load_plugin_textdomain() { - - $plugin_rel_path = apply_filters( 'woocommerce_subscriptions_translation_file_rel_path', dirname( plugin_basename( __FILE__ ) ) . '/languages' ); - - // Then check for a language file in /wp-content/plugins/woocommerce-subscriptions/languages/ (this will be overriden by any file already loaded) - load_plugin_textdomain( 'woocommerce-subscriptions', false, $plugin_rel_path ); - } - - /** - * Loads classes that depend on WooCommerce base classes. - * - * @since 1.2.4 - */ - public static function load_dependant_classes() { - new WCS_Admin_Post_Types(); - new WCS_Admin_Meta_Boxes(); - new WCS_Admin_Reports(); - new WCS_Report_Cache_Manager(); - WCS_Webhooks::init(); - new WCS_Auth(); - WCS_API::init(); - WCS_Template_Loader::init(); - new WCS_Query(); - WCS_Remove_Item::init(); - WCS_User_Change_Status_Handler::init(); - WCS_My_Account_Payment_Methods::init(); - WCS_My_Account_Auto_Renew_Toggle::init(); - - if ( self::is_woocommerce_pre( '3.0' ) ) { - WCS_Product_Legacy::init(); - - // Load WC_DateTime when it doesn't exist yet so we can use it for datetime handling consistently with WC 3.0+ - if ( ! class_exists( 'WC_DateTime' ) ) { - require_once( dirname( __FILE__ ) . '/includes/libraries/class-wc-datetime.php' ); - } - } else { - new WCS_Deprecated_Filter_Hooks(); - } - - // Provide a hook to enable running deprecation handling for stores that might want to check for deprecated code - if ( apply_filters( 'woocommerce_subscriptions_load_deprecation_handlers', false ) ) { - new WCS_Action_Deprecator(); - new WCS_Filter_Deprecator(); - new WCS_Dynamic_Action_Deprecator(); - new WCS_Dynamic_Filter_Deprecator(); - } - - if ( class_exists( 'WCS_Early_Renewal' ) ) { - $notice = new WCS_Admin_Notice( 'error' ); - - // translators: 1-2: opening/closing tags, 3: Subscriptions version. - $notice->set_simple_content( sprintf( __( '%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce Subscriptions%2$s comes with that plugin\'s functionality packaged into the core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to avoid any conflicts.', 'woocommerce-subscriptions' ), '', '', self::$version ) ); - $notice->set_actions( array( - array( - 'name' => __( 'Installed Plugins', 'woocommerce-subscriptions' ), - 'url' => admin_url( 'plugins.php' ), - ), - ) ); - - $notice->display(); - } else { - WCS_Early_Renewal_Manager::init(); - require_once( dirname( __FILE__ ) . '/includes/early-renewal/wcs-early-renewal-functions.php' ); - if ( WCS_Early_Renewal_Manager::is_early_renewal_enabled() ) { - new WCS_Cart_Early_Renewal(); - } - } - - $failed_scheduled_action_manager = new WCS_Failed_Scheduled_Action_Manager( new WC_Logger() ); - $failed_scheduled_action_manager->init(); - - if ( class_exists( 'WC_Abstract_Privacy' ) ) { - new WCS_Privacy(); - } - } - - /** - * Some hooks need to check for the version of WooCommerce, which we can only do after WooCommerce is loaded. - * - * @since 1.5.17 - */ - public static function attach_dependant_hooks() { - - // Redirect the user immediately to the checkout page after clicking "Sign Up Now" buttons to encourage immediate checkout - add_filter( 'woocommerce_add_to_cart_redirect', __CLASS__ . '::add_to_cart_redirect' ); - - if ( self::is_woocommerce_pre( '2.6' ) ) { - // Display Subscriptions on a User's account page - add_action( 'woocommerce_before_my_account', __CLASS__ . '::get_my_subscriptions_template' ); - } - - // Ensure the autoloader knows which API to use. - self::$autoloader->use_legacy_api( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ); - } - - /** - * Displays a notice when Subscriptions is being run on a different site, like a staging or testing site. - * - * @since 1.3.8 - */ - public static function woocommerce_site_change_notice() { - - if ( self::is_duplicate_site() && current_user_can( 'manage_options' ) ) { - - if ( ! empty( $_REQUEST['_wcsnonce'] ) && wp_verify_nonce( $_REQUEST['_wcsnonce'], 'wcs_duplicate_site' ) && isset( $_GET['wc_subscription_duplicate_site'] ) ) { - - if ( 'update' === $_GET['wc_subscription_duplicate_site'] ) { - - WC_Subscriptions::set_duplicate_site_url_lock(); - - } elseif ( 'ignore' === $_GET['wc_subscription_duplicate_site'] ) { - - update_option( 'wcs_ignore_duplicate_siteurl_notice', self::get_current_sites_duplicate_lock() ); - - } - - wp_safe_redirect( remove_query_arg( array( 'wc_subscription_duplicate_site', '_wcsnonce' ) ) ); - - } elseif ( self::get_current_sites_duplicate_lock() !== get_option( 'wcs_ignore_duplicate_siteurl_notice' ) ) { - $notice = new WCS_Admin_Notice( 'error' ); - $notice->set_simple_content( - sprintf( - // translators: 1$-2$: opening and closing tags. 3$-4$: opening and closing link tags for learn more. Leads to duplicate site article on docs. 5$-6$: Opening and closing link to production URL. 7$: Production URL . - esc_html__( 'It looks like this site has moved or is a duplicate site. %1$sWooCommerce Subscriptions%2$s has disabled automatic payments and subscription related emails on this site to prevent duplicate payments from a staging or test environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be the site\'s URL. %3$sLearn more »%4$s.', 'woocommerce-subscriptions' ), - '', '', - '', '', - '', '', - esc_url( self::get_site_url_from_source( 'subscriptions_install' ) ) - ) - ); - $notice->set_actions( array( - array( - 'name' => __( 'Quit nagging me (but don\'t enable automatic payments)', 'woocommerce-subscriptions' ), - 'url' => wp_nonce_url( add_query_arg( 'wc_subscription_duplicate_site', 'ignore' ), 'wcs_duplicate_site', '_wcsnonce' ), - 'class' => 'button button-primary', - ), - array( - 'name' => __( 'Enable automatic payments', 'woocommerce-subscriptions' ), - 'url' => wp_nonce_url( add_query_arg( 'wc_subscription_duplicate_site', 'update' ), 'wcs_duplicate_site', '_wcsnonce' ), - 'class' => 'button', - ), - ) ); - - $notice->display(); - } - } - } - - /** - * A general purpose function for grabbing an array of subscriptions in form of 'subscription_key' => 'subscription_details'. - * - * The $args param is based on the parameter of the same name used by the core WordPress @see get_posts() function. - * It can be used to choose which subscriptions should be returned by the function, how many subscriptions should be returned - * and in what order those subscriptions should be returned. - * - * @param array $args A set of name value pairs to determine the return value. - * 'subscriptions_per_page' The number of subscriptions to return. Set to -1 for unlimited. Default 10. - * 'offset' An optional number of subscription to displace or pass over. Default 0. - * 'orderby' The field which the subscriptions should be ordered by. Can be 'start_date', 'expiry_date', 'end_date', 'status', 'name' or 'order_id'. Defaults to 'start_date'. - * 'order' The order of the values returned. Can be 'ASC' or 'DESC'. Defaults to 'DESC' - * 'customer_id' The user ID of a customer on the site. - * 'product_id' The post ID of a WC_Product_Subscription, WC_Product_Variable_Subscription or WC_Product_Subscription_Variation object - * 'subscription_status' Any valid subscription status. Can be 'any', 'active', 'cancelled', 'suspended', 'expired', 'pending' or 'trash'. Defaults to 'any'. - * @return array Subscription details in 'subscription_key' => 'subscription_details' form. - * @since 1.4 - */ - public static function get_subscriptions( $args = array() ) { - - if ( isset( $args['orderby'] ) ) { - // Although most of these weren't public orderby values, they were used internally so may have been used by developers - switch ( $args['orderby'] ) { - case '_subscription_status': - _deprecated_argument( __METHOD__, '2.0', 'The "_subscription_status" orderby value is deprecated. Use "status" instead.' ); - $args['orderby'] = 'status'; - break; - case '_subscription_start_date': - _deprecated_argument( __METHOD__, '2.0', 'The "_subscription_start_date" orderby value is deprecated. Use "start_date" instead.' ); - $args['orderby'] = 'start_date'; - break; - case 'expiry_date': - case '_subscription_expiry_date': - case '_subscription_end_date': - _deprecated_argument( __METHOD__, '2.0', 'The expiry date orderby value is deprecated. Use "end_date" instead.' ); - $args['orderby'] = 'end_date'; - break; - case 'trial_expiry_date': - case '_subscription_trial_expiry_date': - _deprecated_argument( __METHOD__, '2.0', 'The trial expiry date orderby value is deprecated. Use "trial_end_date" instead.' ); - $args['orderby'] = 'trial_end_date'; - break; - case 'name': - _deprecated_argument( __METHOD__, '2.0', 'The "name" orderby value is deprecated - subscriptions no longer have just one name as they may contain multiple items.' ); - break; - } - } - - _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscriptions( $args )' ); - - $subscriptions = wcs_get_subscriptions( $args ); - - $subscriptions_in_deprecated_structure = array(); - - // Get the subscriptions in the backward compatible structure - foreach ( $subscriptions as $subscription ) { - $subscriptions_in_deprecated_structure[ wcs_get_old_subscription_key( $subscription ) ] = wcs_get_subscription_in_deprecated_structure( $subscription ); - } - - return apply_filters( 'woocommerce_get_subscriptions', $subscriptions_in_deprecated_structure, $args ); - } - - /** - * Returns the longest possible time period - * - * @since 1.3 - */ - public static function get_longest_period( $current_period, $new_period ) { - - if ( empty( $current_period ) || 'year' == $new_period ) { - $longest_period = $new_period; - } elseif ( 'month' === $new_period && in_array( $current_period, array( 'week', 'day' ) ) ) { - $longest_period = $new_period; - } elseif ( 'week' === $new_period && 'day' === $current_period ) { - $longest_period = $new_period; - } else { - $longest_period = $current_period; - } - - return $longest_period; - } - - /** - * Returns the shortest possible time period - * - * @since 1.3.7 - */ - public static function get_shortest_period( $current_period, $new_period ) { - - if ( empty( $current_period ) || 'day' == $new_period ) { - $shortest_period = $new_period; - } elseif ( 'week' === $new_period && in_array( $current_period, array( 'month', 'year' ) ) ) { - $shortest_period = $new_period; - } elseif ( 'month' === $new_period && 'year' === $current_period ) { - $shortest_period = $new_period; - } else { - $shortest_period = $current_period; - } - - return $shortest_period; - } - - - /** - * Returns WordPress/Subscriptions record of the site URL for this site - * - * @param string $source Takes values 'current_wp_site' or 'subscriptions_install' - * @since 2.3.6 - */ - public static function get_site_url_from_source( $source = 'current_wp_site' ) { - // Let the default source be WP - if ( 'subscriptions_install' === $source ) { - $site_url = self::get_site_url(); - } elseif ( ! is_multisite() && defined( 'WP_SITEURL' ) ) { - $site_url = WP_SITEURL; - } else { - $site_url = get_site_url(); - } - - return $site_url; - } - - /** - * Returns Subscriptions record of the site URL for this site - * - * @since 1.3.8 - */ - public static function get_site_url( $blog_id = null, $path = '', $scheme = null ) { - if ( empty( $blog_id ) || ! is_multisite() ) { - $url = get_option( 'wc_subscriptions_siteurl' ); - } else { - switch_to_blog( $blog_id ); - $url = get_option( 'wc_subscriptions_siteurl' ); - restore_current_blog(); - } - - // Remove the prefix used to prevent the site URL being updated on WP Engine - $url = str_replace( '_[wc_subscriptions_siteurl]_', '', $url ); - - $url = set_url_scheme( $url, $scheme ); - - if ( ! empty( $path ) && is_string( $path ) && strpos( $path, '..' ) === false ) { - $url .= '/' . ltrim( $path, '/' ); - } - - return apply_filters( 'wc_subscriptions_site_url', $url, $path, $scheme, $blog_id ); - } - - /** - * Checks if the WordPress site URL is the same as the URL for the site subscriptions normally - * runs on. Useful for checking if automatic payments should be processed. - * - * @since 1.3.8 - */ - public static function is_duplicate_site() { - - $wp_site_url_parts = wp_parse_url( self::get_site_url_from_source( 'current_wp_site' ) ); - $wcs_site_url_parts = wp_parse_url( self::get_site_url_from_source( 'subscriptions_install' ) ); - - if ( ! isset( $wp_site_url_parts['path'] ) && ! isset( $wcs_site_url_parts['path'] ) ) { - $paths_match = true; - } elseif ( isset( $wp_site_url_parts['path'] ) && isset( $wcs_site_url_parts['path'] ) && $wp_site_url_parts['path'] == $wcs_site_url_parts['path'] ) { - $paths_match = true; - } else { - $paths_match = false; - } - - if ( isset( $wp_site_url_parts['host'] ) && isset( $wcs_site_url_parts['host'] ) && $wp_site_url_parts['host'] == $wcs_site_url_parts['host'] ) { - $hosts_match = true; - } else { - $hosts_match = false; - } - - // Check the host and path, do not check the protocol/scheme to avoid issues with WP Engine and other occasions where the WP_SITEURL constant may be set, but being overridden (e.g. by FORCE_SSL_ADMIN) - if ( $paths_match && $hosts_match ) { - $is_duplicate = false; - } else { - $is_duplicate = true; - } - - return apply_filters( 'woocommerce_subscriptions_is_duplicate_site', $is_duplicate ); - } - - - /** - * Include Docs & Settings links on the Plugins administration screen - * - * @param mixed $links - * @since 1.4 - */ - public static function action_links( $links ) { - - $plugin_links = array( - '' . __( 'Settings', 'woocommerce-subscriptions' ) . '', - '' . _x( 'Docs', 'short for documents', 'woocommerce-subscriptions' ) . '', - '' . __( 'Support', 'woocommerce-subscriptions' ) . '', - ); - - return array_merge( $plugin_links, $links ); - } - - /** - * Creates a URL to prevent duplicate payments from staging sites. - * - * The URL can not simply be the site URL, e.g. http://example.com, because WP Engine replaces all - * instances of the site URL in the database when creating a staging site. As a result, we obfuscate - * the URL by inserting '_[wc_subscriptions_siteurl]_' into the middle of it. - * - * We don't use a hash because keeping the URL in the value allows for viewing and editing the URL - * directly in the database. - * - * @since 1.4.2 - * @return string The duplicate lock URL. - */ - public static function get_current_sites_duplicate_lock() { - $site_url = self::get_site_url_from_source( 'current_wp_site' ); - $scheme = parse_url( $site_url, PHP_URL_SCHEME ) . '://'; - $site_url = str_replace( $scheme, '', $site_url ); - - return $scheme . substr_replace( $site_url, '_[wc_subscriptions_siteurl]_', strlen( $site_url ) / 2, 0 ); - } - - /** - * Sets a flag in the database to record the site's url. This then checked to determine if we are on a duplicate - * site or the original/main site, uses @see self::get_current_sites_duplicate_lock(); - * - * @since 1.4.2 - */ - public static function set_duplicate_site_url_lock() { - update_option( 'wc_subscriptions_siteurl', self::get_current_sites_duplicate_lock() ); - } - - /** - * Check if the installed version of WooCommerce is older than a specified version. - * - * @since 1.5.29 - */ - public static function is_woocommerce_pre( $version ) { - - if ( ! defined( 'WC_VERSION' ) || version_compare( WC_VERSION, $version, '<' ) ) { - $woocommerce_is_pre_version = true; - } else { - $woocommerce_is_pre_version = false; - } - - return $woocommerce_is_pre_version; - } - - /** - * Renewals use a lot more memory on WordPress multisite (10-15mb instead of 0.1-1mb) so - * we need to reduce the number of renewals run in each request. - * - * @since version 1.5 - */ - public static function action_scheduler_multisite_batch_size( $batch_size ) { - - if ( is_multisite() ) { - $batch_size = 10; - } - - return $batch_size; - } - - /** - * Include the upgrade notice that will fire when 2.0 is released. - * - * @param array $plugin_data information about the plugin - * @param array $r response from the server about the new version - */ - public static function update_notice( $plugin_data, $r ) { - - // Bail if the update notice is not relevant (new version is not yet 2.0 or we're already on 2.0) - if ( version_compare( '2.0.0', $plugin_data['new_version'], '>' ) || version_compare( '2.0.0', $plugin_data['Version'], '<=' ) ) { - return; - } - - $update_notice = '
    '; - // translators: placeholders are opening and closing tags. Leads to docs on version 2 - $update_notice .= sprintf( __( 'Warning! Version 2.0 is a major update to the WooCommerce Subscriptions extension. Before updating, please create a backup, update all WooCommerce extensions and test all plugins, custom code and payment gateways with version 2.0 on a staging site. %1$sLearn more about the changes in version 2.0 »%2$s', 'woocommerce-subscriptions' ), '', '' ); - $update_notice .= '
    '; - - echo wp_kses_post( $update_notice ); - } - - /** - * Send notice to store admins if they have previously updated Subscriptions to 2.0 and back to v1.5.n. - * - * @since 2.0 - */ - public static function show_downgrade_notice() { - if ( version_compare( get_option( WC_Subscriptions_Admin::$option_prefix . '_active_version', '0' ), self::$version, '>' ) ) { - - echo '
    '; - // translators: placeholder is Subscriptions version number. - echo sprintf( esc_html__( 'Warning! You are running version %s of WooCommerce Subscriptions plugin code but your database has been upgraded to Subscriptions version 2.0. This will cause major problems on your store.', 'woocommerce-subscriptions' ), esc_html( self::$version ) ) . '
    '; - // translators: opening/closing tags - linked to ticket form. - echo sprintf( esc_html__( 'Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer immediately. If you need assistance, after upgrading to Subscriptions v2.0, please %1$sopen a support ticket%2$s.', 'woocommerce-subscriptions' ), '', '' ); - echo '
    '; - - } - } - /* Deprecated Functions */ /** - * Gets a WC_Product using the new core WC @see wc_get_product() function if available, otherwise - * instantiating an instance of the WC_Product class. + * Handle deprecation function calls. * - * @since 1.2.4 - * @deprecated 2.4.0 + * @since 4.0.0 + * + * @param string $function The name of the method being called. + * @param array $arguments An array containing the parameters passed to the method. + * + * @return mixed The value returned from a deprecated function replacement or null. */ - public static function get_product( $product_id ) { - _deprecated_function( __METHOD__, '2.4.0', 'wc_get_product()' ); - return wc_get_product( $product_id ); - } + public static function __callStatic( $method, $arguments ) { + static $deprecation_handler = null; - /** - * Add WooCommerce error or success notice regardless of the version of WooCommerce running. - * - * @param string $message The text to display in the notice. - * @param string $notice_type The singular name of the notice type - either error, success or notice. [optional] - * @since version 1.4.5 - * @deprecated 2.2.16 - */ - public static function add_notice( $message, $notice_type = 'success' ) { - wcs_deprecated_function( __METHOD__, '2.2.16', 'wc_add_notice( $message, $notice_type )' ); - wc_add_notice( $message, $notice_type ); - } - - /** - * Print WooCommerce messages regardless of the version of WooCommerce running. - * - * @since version 1.4.5 - * @deprecated 2.2.16 - */ - public static function print_notices() { - wcs_deprecated_function( __METHOD__, '2.2.16', 'wc_print_notices()' ); - wc_print_notices(); - } - - /** - * Workaround the last day of month quirk in PHP's strtotime function. - * - * @since 1.2.5 - * @deprecated 2.0 - */ - public static function add_months( $from_timestamp, $months_to_add ) { - _deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' ); - return wcs_add_months( $from_timestamp, $months_to_add ); - } - - /** - * A flag to indicate whether the current site has roughly more than 3000 subscriptions. Used to disable - * features on the Manage Subscriptions list table that do not scale well (yet). - * - * Deprecated since querying the new subscription post type is a lot more efficient and no longer puts strain on the database - * - * @since 1.4.4 - * @deprecated 2.0 - */ - public static function is_large_site() { - _deprecated_function( __METHOD__, '2.0' ); - return apply_filters( 'woocommerce_subscriptions_is_large_site', false ); - } - - /** - * Returns the total number of Subscriptions on the site. - * - * @since 1.4 - * @deprecated 2.0 - */ - public static function get_total_subscription_count() { - _deprecated_function( __METHOD__, '2.0' ); - - if ( null === self::$total_subscription_count ) { - self::$total_subscription_count = self::get_subscription_count(); + // Initialise the handler if we dont have one already. + if ( ! $deprecation_handler ) { + $deprecation_handler = new WC_Subscriptions_Deprecation_Handler(); } - return apply_filters( 'woocommerce_get_total_subscription_count', self::$total_subscription_count ); - } + if ( $deprecation_handler->is_deprecated( $method ) ) { + $deprecation_handler->trigger_notice( $method ); - /** - * Returns an associative array with the structure 'status' => 'count' for all subscriptions on the site - * and includes an "all" status, representing all subscriptions. - * - * @since 1.4 - * @deprecated 2.0 - */ - public static function get_subscription_status_counts() { - _deprecated_function( __METHOD__, '2.0' ); - - $results = wp_count_posts( 'shop_subscription' ); - $count = array(); - - foreach ( $results as $status => $count ) { - - if ( in_array( $status, array_keys( wcs_get_subscription_statuses() ) ) || in_array( $status, array( 'trash', 'draft' ) ) ) { - $counts[ $status ] = $count; - } + return $deprecation_handler->call_replacement( $method, $arguments ); + } else { + // Trigger an error consistant with PHP if the function called doesn't exist. + $class = __CLASS__; + $trace = debug_backtrace(); + $file = $trace[0]['file']; + $line = $trace[0]['line']; + trigger_error( "Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR ); //phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped } - - // Order with 'all' at the beginning, then alphabetically - ksort( $counts ); - $counts = array( 'all' => array_sum( $counts ) ) + $counts; - - return apply_filters( 'woocommerce_subscription_status_counts', $counts ); - } - - /** - * Takes an array of filter params and returns the number of subscriptions which match those params. - * - * @since 1.4 - * @deprecated 2.0 - */ - public static function get_subscription_count( $args = array() ) { - _deprecated_function( __METHOD__, '2.0' ); - - $args['subscriptions_per_page'] = -1; - $subscription_count = 0; - - if ( ( ! isset( $args['subscription_status'] ) || in_array( $args['subscription_status'], array( 'all', 'any' ) ) ) && ( isset( $args['include_trashed'] ) && true === $args['include_trashed'] ) ) { - - $args['subscription_status'] = 'trash'; - $subscription_count += count( wcs_get_subscriptions( $args ) ); - $args['subscription_status'] = 'any'; - } - - $subscription_count += count( wcs_get_subscriptions( $args ) ); - - return apply_filters( 'woocommerce_get_subscription_count', $subscription_count, $args ); - } - - /** - * which was called @see woocommerce_format_total() prior to WooCommerce 2.1. - * - * Deprecated since we no longer need to support the workaround required for WC versions < 2.1 - * - * @since version 1.4.6 - * @deprecated 2.0 - */ - public static function format_total( $number ) { - _deprecated_function( __METHOD__, '2.0', 'wc_format_decimal()' ); - return wc_format_decimal( $number ); - } - - /** - * Displays a notice to upgrade if using less than the ideal version of WooCommerce - * - * @since 1.3 - */ - public static function woocommerce_dependancy_notice() { - _deprecated_function( __METHOD__, '2.1', __CLASS__ . '::woocommerce_inactive_notice()' ); } } +/** + * Add woocommerce_inbox_variant for the Remote Inbox Notification. + * + * P2 post can be found at https://wp.me/paJDYF-1uJ. + */ +if ( ! function_exists( 'add_woocommerce_inbox_variant' ) ) { + function add_woocommerce_inbox_variant() { + $config_name = 'woocommerce_inbox_variant_assignment'; + if ( false === get_option( $config_name, false ) ) { + update_option( $config_name, wp_rand( 1, 12 ) ); + } + } +} +add_action( 'woocommerce_subscriptions_upgraded', 'add_woocommerce_inbox_variant', 10 ); +register_activation_hook( __FILE__, 'add_woocommerce_inbox_variant' ); + + +/** + * Load and set up the Autoloader + * + * If the `woocommerce-subscriptions-core` plugin is active, setup the autoloader using this plugin directory + * as the base file path for loading subscription core classes. + * + * @since 4.0.0 + * @return WCS_Autoloader + */ +function wcs_init_autoloader() { + if ( ! function_exists( 'is_plugin_active' ) ) { + include_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + $wcs_core_plugin_slug = 'woocommerce-subscriptions-core/woocommerce-subscriptions-core.php'; + $is_wcs_core_active = ( isset( $_GET['action'], $_GET['plugin'] ) && 'activate' === $_GET['action'] && $wcs_core_plugin_slug === $_GET['plugin'] ) || is_plugin_active( $wcs_core_plugin_slug ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended + $wcs_core_path = $is_wcs_core_active ? WP_PLUGIN_DIR . '/woocommerce-subscriptions-core/' : dirname( __FILE__ ) . '/vendor/woocommerce/subscriptions-core/'; + + require_once $wcs_core_path . 'includes/class-wcs-core-autoloader.php'; + require_once dirname( __FILE__ ) . '/includes/class-wcs-autoloader.php'; + + $wcs_autoloader = new WCS_Autoloader( $wcs_core_path ); + $wcs_autoloader->register(); + + return $wcs_autoloader; +} + WC_Subscriptions::init( $wcs_autoloader );