From 954d7ffb36d5259172e986edd2cfa1c027435b17 Mon Sep 17 00:00:00 2001 From: Woo Date: Tue, 23 Apr 2024 18:27:54 +0000 Subject: [PATCH] Updates to 1.15.1 --- assets/css/admin/wc-product-documents.min.css | 1 + .../css/frontend/wc-product-documents.min.css | 1 + assets/images/draggable-handle.png | Bin 0 -> 98 bytes assets/images/product-data-icon.png | Bin 0 -> 200 bytes assets/js/admin/wc-product-documents.js | 222 ++ assets/js/admin/wc-product-documents.min.js | 1 + changelog.txt | 114 + class-wc-product-documents.php | 411 +++ .../woocommerce-product-documents-it_IT.mo | Bin 0 -> 3190 bytes .../woocommerce-product-documents-it_IT.po | 157 ++ .../woocommerce-product-documents.pot | 144 ++ readme.txt | 30 + src/Lifecycle.php | 63 + .../class-wc-product-documents-admin.php | 445 ++++ src/class-wc-product-documents-collection.php | 432 ++++ ...ss-wc-product-documents-shortcode-list.php | 122 + .../class-wc-product-documents-shortcode.php | 108 + src/wc-product-documents-template.php | 129 + ...-wc-product-documents-widget-documents.php | 137 + .../single-product/product-documents.php | 65 + .../skyverge/wc-plugin-framework/license.txt | 694 +++++ .../woocommerce/Addresses/Address.php | 292 +++ .../Addresses/Customer_Address.php | 150 ++ .../woocommerce/Country_Helper.php | 661 +++++ .../woocommerce/Handlers/Script_Handler.php | 343 +++ .../woocommerce/Lifecycle.php | 668 +++++ .../Settings_API/Abstract_Settings.php | 537 ++++ .../woocommerce/Settings_API/Control.php | 271 ++ .../woocommerce/Settings_API/Setting.php | 479 ++++ .../woocommerce/admin/Notes_Helper.php | 150 ++ ...stract-sv-wc-plugin-admin-setup-wizard.php | 1299 ++++++++++ .../api/Abstract_Cacheable_API_Base.php | 273 ++ .../api/abstract-sv-wc-api-json-request.php | 135 + .../api/abstract-sv-wc-api-json-response.php | 105 + .../api/abstract-sv-wc-api-xml-request.php | 200 ++ .../api/abstract-sv-wc-api-xml-response.php | 138 + .../woocommerce/api/class-sv-wc-api-base.php | 867 +++++++ .../api/class-sv-wc-api-exception.php | 38 + .../api/interface-sv-wc-api-request.php | 97 + .../api/interface-sv-wc-api-response.php | 59 + .../api/traits/Cacheable_Request_Trait.php | 161 ++ .../sv-wc-plugin-admin-setup-wizard.min.css | 1 + .../woocommerce/assets/images/ajax-loader.gif | Bin 0 -> 885 bytes .../sv-wc-plugin-admin-setup-wizard.min.js | 1 + .../sv-wp-admin-job-batch-handler.min.js | 1 + .../woocommerce/changelog.txt | 442 ++++ .../class-sv-wc-admin-notice-handler.php | 436 ++++ .../class-sv-wc-framework-bootstrap.php | 407 +++ .../woocommerce/class-sv-wc-helper.php | 1104 ++++++++ .../class-sv-wc-hook-deprecator.php | 199 ++ .../class-sv-wc-plugin-compatibility.php | 367 +++ .../class-sv-wc-plugin-dependencies.php | 523 ++++ .../class-sv-wc-plugin-exception.php | 38 + .../woocommerce/class-sv-wc-plugin.php | 1311 ++++++++++ .../class-sv-wp-admin-message-handler.php | 438 ++++ .../abstract-sv-wc-data-compatibility.php | 43 + .../class-sv-wc-order-compatibility.php | 522 ++++ ...class-sv-wc-subscription-compatibility.php | 140 + .../woocommerce-plugin-framework-et.mo | Bin 0 -> 19127 bytes .../woocommerce-plugin-framework-et.po | 2296 +++++++++++++++++ .../woocommerce-plugin-framework.pot | 2034 +++++++++++++++ .../wc-plugin-framework/woocommerce/index.php | 29 + .../rest-api/Controllers/Settings.php | 383 +++ .../rest-api/class-sv-wc-plugin-rest-api.php | 162 ++ .../utilities/class-sv-wp-async-request.php | 192 ++ .../class-sv-wp-background-job-handler.php | 1136 ++++++++ .../class-sv-wp-job-batch-handler.php | 310 +++ woocommerce-product-documents.php | 390 +++ 68 files changed, 23104 insertions(+) create mode 100644 assets/css/admin/wc-product-documents.min.css create mode 100644 assets/css/frontend/wc-product-documents.min.css create mode 100644 assets/images/draggable-handle.png create mode 100644 assets/images/product-data-icon.png create mode 100644 assets/js/admin/wc-product-documents.js create mode 100644 assets/js/admin/wc-product-documents.min.js create mode 100644 changelog.txt create mode 100644 class-wc-product-documents.php create mode 100644 i18n/languages/woocommerce-product-documents-it_IT.mo create mode 100644 i18n/languages/woocommerce-product-documents-it_IT.po create mode 100644 i18n/languages/woocommerce-product-documents.pot create mode 100644 readme.txt create mode 100644 src/Lifecycle.php create mode 100644 src/admin/class-wc-product-documents-admin.php create mode 100644 src/class-wc-product-documents-collection.php create mode 100644 src/shortcodes/class-wc-product-documents-shortcode-list.php create mode 100644 src/shortcodes/class-wc-product-documents-shortcode.php create mode 100755 src/wc-product-documents-template.php create mode 100644 src/widgets/class-wc-product-documents-widget-documents.php create mode 100644 templates/single-product/product-documents.php create mode 100644 vendor/skyverge/wc-plugin-framework/license.txt create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Address.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Customer_Address.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Country_Helper.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Handlers/Script_Handler.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Abstract_Settings.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Control.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Setting.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/admin/Notes_Helper.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/Abstract_Cacheable_API_Base.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-request.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-response.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-request.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-response.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-base.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-exception.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/interface-sv-wc-api-request.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/interface-sv-wc-api-response.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/api/traits/Cacheable_Request_Trait.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/assets/css/admin/sv-wc-plugin-admin-setup-wizard.min.css create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/assets/images/ajax-loader.gif create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/assets/js/admin/sv-wc-plugin-admin-setup-wizard.min.js create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/assets/js/admin/sv-wp-admin-job-batch-handler.min.js create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/changelog.txt create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-admin-notice-handler.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-helper.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-hook-deprecator.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-compatibility.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-exception.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wp-admin-message-handler.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/abstract-sv-wc-data-compatibility.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/class-sv-wc-order-compatibility.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/class-sv-wc-subscription-compatibility.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.mo create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.po create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework.pot create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/index.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/rest-api/Controllers/Settings.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/rest-api/class-sv-wc-plugin-rest-api.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-async-request.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php create mode 100644 vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-job-batch-handler.php create mode 100644 woocommerce-product-documents.php diff --git a/assets/css/admin/wc-product-documents.min.css b/assets/css/admin/wc-product-documents.min.css new file mode 100644 index 0000000..ec47fa4 --- /dev/null +++ b/assets/css/admin/wc-product-documents.min.css @@ -0,0 +1 @@ +@import url("//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css");#woocommerce-product-data ul.product_data_tabs li.wc-product-documents-tab a:before{font-family:FontAwesome;font-weight:400;font-style:normal;font-variant:normal;text-transform:none;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;line-height:1;content:"\f0f6"}#woocommerce-product-data .wc-product-documents-section .product_documents_section_name{width:100px;float:none}#woocommerce-product-data .wc-product-documents-section .product-documents-default-section{width:auto;float:none}#woocommerce-product-data .wc-product-documents-section label.product-documents-default-section{padding:0 5px 0 10px;margin-left:0}#woocommerce-product-data .wc-product-documents-section input.product-documents-default-section{margin-top:2px}#woocommerce-product-data .wc-product-documents-section .wc-metabox-content{background-color:#fff;padding:5px}#woocommerce-product-data .wc-product-documents-section table.wc-product-documents{padding:0}#woocommerce-product-data .wc-product-documents-section table.wc-product-documents td{padding:10px 7px;cursor:move}#woocommerce-product-data .wc-product-documents-section table.wc-product-documents td,#woocommerce-product-data .wc-product-documents-section table.wc-product-documents th{border-left-style:solid;border-right-style:solid;border-left-width:0;border-right-width:0;border-bottom:1px solid #dfdfdf;border-top:1px solid #fff}#woocommerce-product-data .wc-product-documents-section table.wc-product-documents td.wc-product-document-actions button,#woocommerce-product-data .wc-product-documents-section table.wc-product-documents th.wc-product-document-actions button{margin-right:5px}#woocommerce-product-data .wc-product-documents-section table.wc-product-documents td.wc-product-document-draggable{vertical-align:middle;text-align:center}#woocommerce-product-data .wc-product-documents-section table.wc-product-documents input{min-width:0}#woocommerce-product-data #wc-product-documents-data .expand-close{margin-right:2px;color:#777;font-size:12px;font-style:italic;zoom:1}#woocommerce-product-data #wc-product-documents-data .expand-close a{background:none;padding:0;font-size:12px;text-decoration:none;float:right;margin-left:14px;line-height:22px}#woocommerce-product-data #wc-product-documents-data .expand-close:after,#woocommerce-product-data #wc-product-documents-data .expand-close:before{content:" ";display:table}#woocommerce-product-data #wc-product-documents-data .expand-close:after{clear:both} \ No newline at end of file diff --git a/assets/css/frontend/wc-product-documents.min.css b/assets/css/frontend/wc-product-documents.min.css new file mode 100644 index 0000000..89eea0d --- /dev/null +++ b/assets/css/frontend/wc-product-documents.min.css @@ -0,0 +1 @@ +.widget-area .widget .woocommerce-product-documents h3,.widget-area .widget .woocommerce-product-documents ul,.woocommerce-product-documents h3,.woocommerce-product-documents ul,h3.woocommerce-product-documents-title{margin-bottom:0}.entry-summary .widget-area .widget .woocommerce-product-documents,.entry-summary .woocommerce-product-documents{margin-bottom:15px}.widget-area .widget .woocommerce-product-documents .ui-accordion-header,.woocommerce-product-documents .ui-accordion-header{background-image:none} \ No newline at end of file diff --git a/assets/images/draggable-handle.png b/assets/images/draggable-handle.png new file mode 100644 index 0000000000000000000000000000000000000000..43e254ec58eef95b069cbbb21f1d0d86826e8cff GIT binary patch literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^LLfE=8<1S$XD11yG(BA$Lp07O@2UCush&-XL5)p| wah2qeAFr;iKKN8=+I0Q+KDKWe3Bg=wV~cW|q0Rk_4G`GU3T%1+tGK<yy85}Sb4q9e00h-f AcmMzZ literal 0 HcmV?d00001 diff --git a/assets/js/admin/wc-product-documents.js b/assets/js/admin/wc-product-documents.js new file mode 100644 index 0000000..5f7fb23 --- /dev/null +++ b/assets/js/admin/wc-product-documents.js @@ -0,0 +1,222 @@ +jQuery( function( $ ) { + + 'use strict'; + + /* global confirm, wc_product_documents_admin_params */ + + // Open/close + $( '#wc-product-documents-data .wc-metaboxes-wrapper' ) + .on( 'click', '.expand_all', function() { + $( this ).closest('.wc-metaboxes-wrapper').find( '.wc-metabox > .wc-metabox-content' ).show(); + return false; + } ) + .on( 'click', '.close_all', function(){ + $( this ).closest( '.wc-metaboxes-wrapper' ).find( '.wc-metabox > .wc-metabox-content' ).hide(); + return false; + } ); + + + $( '#wc-product-documents-data' ) + // add a new document section + .on( 'click', '.add-new-product-documents-section', function() { + + var index = -1; + + // find the largest current section index (if any) + $( '.wc-product-documents-sections .wc-product-documents-section .product-documents-section-index' ).each( function() { + var value = parseInt( $( this ).val(), 10 ); + index = ( value > index ) ? value : index; + } ); + + index++; + + var html = wc_product_documents_admin_params.new_section.replace( /{index}/g, index ); + + $( '.wc-product-documents-sections' ).append( html ); + updateDocumentSectionRowIndexes(); + setDefaultDocumentSection(); + + return false; + } ) + // remove a document section + .on( 'click', '.remove-wc-product-documents-section', function() { + + var answer = confirm( wc_product_documents_admin_params.confirm_remove_section_text ); + + if ( answer ) { + var section = $( this ).closest( '.wc-product-documents-section' ); + $( section ).remove(); + + updateDocumentSectionRowIndexes(); + setDefaultDocumentSection(); + } + + return false; + } ); + + + // Make the document sections sortable + $( '.wc-product-documents-sections' ).sortable( { + items: '.wc-product-documents-section', + cursor: 'move', + axis: 'y', + handle: 'h3', + scrollSensitivity: 40, + helper: function( e, ui ) { + return ui; + }, + start: function( event, ui ) { + ui.item.css( 'border-style', 'dashed' ); + }, + stop: function( event, ui ) { + ui.item.removeAttr( 'style' ); + updateDocumentSectionRowIndexes(); + } + } ); + + + // update the product tab indexes, based on the current section ordering + function updateDocumentSectionRowIndexes() { + $( '.wc-product-documents-sections .wc-product-documents-section' ).each( + function( index, el ) { + $( '.product-documents-section-position', el ).val( parseInt( $( el ).index( '.wc-product-documents-sections .wc-product-documents-section' ), 10 ) ); + } + ); + } + + + // ensure a default is set + function setDefaultDocumentSection() { + var $radios = $( 'input:radio[name=product_documents_default_section]' ); + + if ( $radios.is( ':checked' ) === false ) { + $radios.filter( '[value=0]' ).prop( 'checked', true ); + } + } + + + /* Documents Handling */ + + + $( '#wc-product-documents-data' ) + // add a new document row + .on( 'click', '.wc-product-documents-add-document', function() { + + var $parentSection = $( this ).closest( '.wc-product-documents-section' ); + var index = $( '.product-documents-section-index', $parentSection ).val(); + + var subIndex = -1; + + // find the largest current section index (if any) + $( '.wc-product-document .wc-product-document-sub-index', $parentSection ).each( function() { + var value = parseInt( $( this ).val(), 10 ); + subIndex = ( value > subIndex ) ? value : subIndex; + } ); + + subIndex++; + + var html = wc_product_documents_admin_params.new_document.replace( /{index}/g, index ).replace( /{sub_index}/g, subIndex ); + + $( this ).closest( '.wc-product-documents' ).append( html ); + updateDocumentRowIndexes( $parentSection ); + setAttachFileHandler(); + + return false; + } ) + // remove a document + .on( 'click', '.wc-product-documents-remove-document', function() { + + var answer = confirm( wc_product_documents_admin_params.confirm_remove_document_text ); + + if ( answer ) { + var $parentSection = $( this ).closest( '.wc-product-documents-section' ); + var $documentRow = $( this ).closest( '.wc-product-document' ); + $documentRow.remove(); + + updateDocumentRowIndexes( $parentSection ); + } + + return false; + } ); + + + // product document ordering + $( 'table.wc-product-documents tbody' ).sortable( { + items : 'tr', + cursor : 'move', + axis : 'y', + handle : 'td', + scrollSensitivity : 40, + helper: function( e, ui ) { + return ui; + }, + start: function( event, ui ) { + ui.item.css( 'background-color','#f6f6f6' ); + }, + stop: function( event, ui ) { + ui.item.removeAttr( 'style' ); + updateDocumentRowIndexes(); + } + } ); + + + // update the product document table row positions, based on the current ordering + function updateDocumentRowIndexes( $section ) { + $( '.wc-product-documents .wc-product-document', $section ).each( + function( index, el ) { + $( '.wc-product-document-position', el ).val( parseInt( $( el ).index( '.wc-product-documents .wc-product-document' ), 10 ) ); + } + ); + } + + + /* File Upload */ + + var file_frame; + var $currentDocumentRow; + + /** + * Add handlers to the "Select a File" inputs, to launch the media browser + */ + function setAttachFileHandler() { + + $( '#wc-product-documents-data .wc-product-documents-set-file' ).on( 'click', function( event ) { + + event.preventDefault(); + + // save the element that was clicked on so we can set the image + $currentDocumentRow = $( event.target ).closest( 'tr' ); + + // If the media frame already exists, reopen it. + if ( file_frame ) { + file_frame.open(); + return; + } + + // Create the media frame. + file_frame = wp.media.frames.file_frame = wp.media( { + title: wc_product_documents_admin_params.select_file_text, + button: { + text: wc_product_documents_admin_params.set_file_text + }, + multiple: false + } ); + + // When an image is selected, run a callback. + file_frame.on( 'select', function() { + // We set multiple to false so only get one image from the uploader + var attachment = file_frame.state().get( 'selection' ).first().toJSON(); + + // Set the file id/display the file url + $( 'input.wc-product-document-file-location', $currentDocumentRow ).val( attachment.url ); + }); + + // Finally, open the modal + file_frame.open(); + }); + } + + // Initialize + setAttachFileHandler(); + +} ); diff --git a/assets/js/admin/wc-product-documents.min.js b/assets/js/admin/wc-product-documents.min.js new file mode 100644 index 0000000..dec8d9e --- /dev/null +++ b/assets/js/admin/wc-product-documents.min.js @@ -0,0 +1 @@ +"use strict";jQuery(function(o){function e(){o(".wc-product-documents-sections .wc-product-documents-section").each(function(t,c){o(".product-documents-section-position",c).val(parseInt(o(c).index(".wc-product-documents-sections .wc-product-documents-section"),10))})}function n(){var t=o("input:radio[name=product_documents_default_section]");!1===t.is(":checked")&&t.filter("[value=0]").prop("checked",!0)}function s(t){o(".wc-product-documents .wc-product-document",t).each(function(t,c){o(".wc-product-document-position",c).val(parseInt(o(c).index(".wc-product-documents .wc-product-document"),10))})}var c,u;function d(){o("#wc-product-documents-data .wc-product-documents-set-file").on("click",function(t){t.preventDefault(),u=o(t.target).closest("tr"),c||(c=wp.media.frames.file_frame=wp.media({title:wc_product_documents_admin_params.select_file_text,button:{text:wc_product_documents_admin_params.set_file_text},multiple:!1})).on("select",function(){var t=c.state().get("selection").first().toJSON();o("input.wc-product-document-file-location",u).val(t.url)}),c.open()})}o("#wc-product-documents-data .wc-metaboxes-wrapper").on("click",".expand_all",function(){return o(this).closest(".wc-metaboxes-wrapper").find(".wc-metabox > .wc-metabox-content").show(),!1}).on("click",".close_all",function(){return o(this).closest(".wc-metaboxes-wrapper").find(".wc-metabox > .wc-metabox-content").hide(),!1}),o("#wc-product-documents-data").on("click",".add-new-product-documents-section",function(){var c=-1,t=(o(".wc-product-documents-sections .wc-product-documents-section .product-documents-section-index").each(function(){var t=parseInt(o(this).val(),10);c=c 'woocommerce-product-documents', + 'supports_hpos' => true, + ] + ); + + $this->includes(); + + // display any product documents on the product pages + add_action( 'woocommerce_single_product_summary', array( $this, 'render_product_documents' ), 25 ); + + // register widgets + add_action( 'widgets_init', array( $this, 'register_widgets' ) ); + } + + + /** + * Builds the lifecycle handler instance. + * + * @since 1.9.0 + */ + protected function init_lifecycle_handler() { + + require_once( $this->get_plugin_path() . '/src/Lifecycle.php' ); + + $this->lifecycle_handler = new SkyVerge\WooCommerce\Product_Documents\Lifecycle( $this ); + } + + + /** + * Initializes the plugin. + * + * @internal + * + * @since 1.9.0 + */ + public function init_plugin() { + + // add accordion shortcode + add_shortcode( 'woocommerce_product_documents', array( $this, 'product_documents_shortcode' ) ); + // add products list shortcode + add_shortcode( 'woocommerce_product_documents_list', array( $this, 'product_documents_shortcode_list' ) ); + } + + + /** + * Registers product documents widgets. + * + * @internal + * + * @since 1.0 + */ + public function register_widgets() { + + // load widget + require_once( $this->get_plugin_path() . '/src/widgets/class-wc-product-documents-widget-documents.php' ); + + // register widget + register_widget( 'WC_Product_Documents_Widget_Documents' ); + } + + + /** + * Handles the Product Documents shortcode. + * + * Renders the product documents UI element. + * + * @since 1.0 + * + * @param array $atts associative array of shortcode parameters + * @return string shortcode content (may include HTML) + */ + public function product_documents_shortcode( $atts ) { + + require_once( $this->get_plugin_path() . '/src/shortcodes/class-wc-product-documents-shortcode.php' ); + + return \WC_Shortcodes::shortcode_wrapper( array( 'WC_Product_Documents_Shortcode', 'output' ), $atts ); + } + + + /** + * Handles the products list shortcode. + * + * Renders a list of products with their documents. + * + * @internal + * + * @since 1.2.0 + * + * @param array $atts associative array of shortcode parameters + * @return string shortcode content (may include HTML) + */ + public function product_documents_shortcode_list( $atts ) { + + require_once( $this->get_plugin_path() . '/src/shortcodes/class-wc-product-documents-shortcode-list.php' ); + + return \WC_Shortcodes::shortcode_wrapper( array( 'WC_Product_Documents_List_Shortcode', 'output' ), $atts ); + } + + + /** + * Includes required files. + * + * @since 1.0 + */ + private function includes() { + + // include template & helper functions + require_once( $this->get_plugin_path() . '/src/wc-product-documents-template.php' ); + // include main objects + require_once( $this->get_plugin_path() . '/src/class-wc-product-documents-collection.php' ); + + if ( is_admin() && ! wp_doing_ajax() ) { + // include admin classes + $this->admin_includes(); + } + } + + + /** + * Includes required admin files. + * + * @since 1.0 + */ + private function admin_includes() { + + $this->admin = $this->load_class( '/src/admin/class-wc-product-documents-admin.php', 'WC_Product_Documents_Admin' ); + } + + + /** + * Renders any product documents. + * + * @internal + * + * @since 1.0 + */ + public function render_product_documents() { + global $post; + + if ( $post && $this->render_documents_on_product_page( $post->ID ) ) { + + woocommerce_product_documents_template( $post->ID, $this->get_documents_title_text( $post->ID ) ); + } + } + + + /** + * Determines whether the product documents element should be rendered on the product page. + * + * @since 1.0 + * + * @param int $product_id product identifier + * @return bool + */ + public function render_documents_on_product_page( $product_id ) { + + $product = $product_id > 0 ? wc_get_product( $product_id ) : null; + + return $product && 'yes' === $product->get_meta( '_wc_product_documents_display' ); + } + + + /** + * Gets the admin handler. + * + * @since 1.6.0 + * + * @return \WC_Product_Documents_Admin + */ + public function get_admin_instance() { + + return $this->admin; + } + + + /** + * Returns the main Product Documents instance. + * + * Ensures only one instance is/can be loaded. + * + * @since 1.3.0 + * + * @return \WC_Product_Documents + */ + public static function instance() { + + if ( null === self::$instance ) { + + self::$instance = new self(); + } + + return self::$instance; + } + + + /** + * Gets the plugin configuration URL. + * + * @since 1.0 + * + * @param string|null $_ unused + * @return string plugin settings URL + */ + public function get_settings_url( $_ = null ) { + + return admin_url( 'admin.php?page=wc-settings&tab=products' ); + } + + + /** + * Gets the plugin sales page URL. + * + * @since 1.9.0 + * + * @return string + */ + public function get_sales_page_url() { + + return 'https://woocommerce.com/products/product-documents/'; + } + + + /** + * Gets the plugin name, localized. + * + * @since 1.1 + * + * @return string the plugin name + */ + public function get_plugin_name() { + + return __( 'WooCommerce Product Documents', 'woocommerce-product-documents' ); + } + + + /** + * Returns __FILE__. + * + * @since 1.1 + * + * + * @return string the full path and filename of the plugin file + */ + protected function get_file() { + + return __FILE__; + } + + + /** + * Gets the plugin documentation url. + * + * @since 1.4.0 + * + * @return string documentation URL + */ + public function get_documentation_url() { + + return 'https://docs.woocommerce.com/document/woocommerce-product-documents/'; + } + + /** + * Gets the plugin support URL. + * + * @since 1.4.0 + * + * @return string + */ + public function get_support_url() { + + return 'https://woocommerce.com/my-account/marketplace-ticket-form/'; + } + + + /** + * Gets the documents title text for the identified product, if any. + * + * @since 1.1 + * + * @param int $product_id product identifier + * @return string documents title text + */ + public function get_documents_title_text( $product_id ) { + + // title configured for product? + $product = $product_id > 0 ? wc_get_product( $product_id ) : null; + $title = $product ? $product->get_meta( '_wc_product_documents_title' ) : null; + + // use global default if not found + return stripslashes( (string) ! $title ? get_option( 'wc_product_documents_title', '' ) : $title ); + } + + + /** + * Determines if a product can be accessed for outputting documents data. + * + * This is mainly used by shortcodes. + * + * @since 1.15.1 + * + * @param WC_Product $product + * @return bool + */ + public function is_product_accessible( \WC_Product $product ) : bool { + + // bail for products accessible by admins or editable by the user + if ( current_user_can( 'manage_woocommerce' ) || current_user_can( 'edit_product', $product->get_id() ) ) { + + $is_accessible = true; + + // product is not meant to be visible or is unpublished + } elseif ( ! $product->is_visible() || get_post_status( $product->get_id() ) !== 'publish' ) { + + $is_accessible = false; + + } else { + + $is_accessible = true; + $product_post = get_post( $product->get_id() ); + + // product is password-protected + if ( $product_post && ! empty( $product_post->post_password ) && post_password_required( $product_post->ID ) ) { + $is_accessible = false; + } + } + + /** + * Filters whether a product can be accessed for outputting the shortcode data. + * + * @since 1.15.1 + * + * @param bool $is_accessible + * @param WC_Product $product + */ + return (bool) apply_filters( 'wc_product_documents_is_product_accessible', $is_accessible, $product ); + } + + +} + + +/** + * Returns the One True Instance of Product Documents. + * + * @since 1.3.0 + * + * @return \WC_Product_Documents + */ +function wc_product_documents() { + + return \WC_Product_Documents::instance(); +} diff --git a/i18n/languages/woocommerce-product-documents-it_IT.mo b/i18n/languages/woocommerce-product-documents-it_IT.mo new file mode 100644 index 0000000000000000000000000000000000000000..9e70a2dd2a645a6e3e8f2379a8800c329958fbf6 GIT binary patch literal 3190 zcma);ONbm*6ozj!(KyCed_|4sf{03}ek2hl9YUDQj53gklbMcY7j9RbuD(uH-A>(G z-Dwx@6vTxaT^m>GRzYwn5nQ+v%}x;o7lI4Xl?3!Z_2{n2Btwd+{_1(oe;)VL{Jekn zhXUI(*bidgw@Zi@!RsJzSMCtvZt!DpANUz~68sWufd7CV`0SlRJOG{p?*SFa?`?u> zpamZSzX3l1uYq&mTf2qW1HKF5PrQ$xd%+Jte*Ox02>cv;9Q+=<3;YAT5Bv+<3;qW_ z2JVG1K0gGq-xok1oPhWfKjG(T@Hg;Da2Jf71`mSoAm)o8+y5Qn_k(|eU6747f%728 z`!@J6_yx#$`4(i|KY*9OUqH_1I+F1nXh7C`0zq?rRzOG=8z5i50J6V6_#8L^p8!7s zIgej~?C)!k{ryva@s_j5|@Ce8?Vcpfnv9SFIu|I`9uK|ei<{ME-NHQ_w5)@tMU zICieLSn!=Ti4_Y$AeW4v#gsTcu~NxlYJ$vnGAOTGNfGe_(i!=>F^eXSDfMak;82AG zQz^-b$)wH7gRv@JNhvlXl5U{w)aI$%d)!j4^ORVOw7<#zoe9H;aBeI~6-8o+`YMZ@ zSkiVFsR{I3a?Skf|O$rqx{VYv6oGMV=mnNwN&ha!vl@__C+@N`W{ft;nR4*z6 zffSWF6Dy~E$e75W@}J;%nz_Oy0rlO{E=})cGcW^5x4zmEd7y=Zxx6B+jas#9124jUu0-@>j)Zw_lNEVr5r5 zBz)T&<@NQvxMBk>f|gP8WsQe7AgMSQnDI2YnX`?}$!nB`B)Z%ajxHmDAvdIoeBWe=YsMm&lZTGSv4?8J&AGK#yWV0-SOzBXmXxE8Jkn|(_geE_`)wR;SgP zTU}XQo+)la(4t8kmZI044Dlv+LK9AOazgq8m0~5I%v|4_pFNkV#P%ummJ{^4PQs3y z?`a1a-a3smr=qT+-SXP=vi(x$XzOrm9tzGV3ukO3QqH6ui7QE%VZnP{QgQ9PBelD@ z(w)2Dy+R44#nWqs0`26H#*xOcIkE62+-b28hB`|^JsqT`xUN&zVaY*I zF=2fSe;D;u+|w$>lpW{{u3YAvM$=J1eVu4$#Hz6_RftX@DrnDbu&T=a4e_y6U5nQ@ z`2@x)CmF$M5&6|mbBj00Lqn|Li(^vELnASY^CVTiknWz2v{O|M*jt<{L|$f7nm=I} zB^->rrP73=nV@=&8gk{9(HUz^f+{9HrUhmQ*P{>sSIQw(C=s+H1?9k2!=bUrB*Mw? zW_@^D9^O^bm$BFeG*zO#$LTrC5hKY zoKJZckE}<}mlK`OZdI#>*y7\n" +"Language-Team: LANGUAGE \n" + +#. Plugin Name of the plugin/theme +msgid "WooCommerce Product Documents" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:109 +#: src/admin/class-wc-product-documents-admin.php:121 +#: src/admin/class-wc-product-documents-admin.php:195 +#: src/admin/class-wc-product-documents-admin.php:202 +msgid "Product Documents" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:117 +msgid "Product Documents Default Title" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:118 +msgid "" +"This text will be shown above the product documents section unless " +"overridden at the product level." +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:168 +msgid "Are you sure you want to remove this section?" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:169 +msgid "Are you sure you want to remove this document?" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:170 +msgid "Select a File" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:171 +#: src/admin/class-wc-product-documents-admin.php:372 +msgid "Set File" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:233 +msgid "Product Documents Title" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:234 +msgid "" +"This text optional will be shown as the title for the product documents " +"element." +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:244 +msgid "Show Product Documents" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:245 +msgid "" +"Enable this to automatically display any documents for this product on the " +"product page. Product documents can also be displayed anywhere via the " +"widget or shortcode." +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:254 +msgid "Close all" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:255 +msgid "Expand all" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:266 +msgid "New Section" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:295 +#: src/admin/class-wc-product-documents-admin.php:373 +msgid "Remove" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:296 +msgid "Click to toggle" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:297 +msgid "Name" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:298 +msgid "Default" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:310 +msgid "Label" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:311 +msgid "Document Path/URL" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:312 +msgid "Actions" +msgstr "" + +#: src/admin/class-wc-product-documents-admin.php:326 +msgid "Add Document" +msgstr "" + +#: src/widgets/class-wc-product-documents-widget-documents.php:46 +msgid "" +"Display a set of product documents for the current product if on a product " +"page." +msgstr "" + +#: src/widgets/class-wc-product-documents-widget-documents.php:130 +msgid "Title" +msgstr "" + +#. Plugin URI of the plugin/theme +msgid "http://www.woocommerce.com/products/woocommerce-product-documents/" +msgstr "" + +#. Description of the plugin/theme +msgid "Adds a product documents element to WooCommerce product pages" +msgstr "" + +#. Author of the plugin/theme +msgid "SkyVerge" +msgstr "" + +#. Author URI of the plugin/theme +msgid "http://www.woocommerce.com" +msgstr "" \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..6583047 --- /dev/null +++ b/readme.txt @@ -0,0 +1,30 @@ +=== WooCommerce Product Documents === +Author: skyverge +Tags: woocommerce +Requires at least: 5.6 +Tested up to: 6.4.3 +Requires PHP: 7.4 + +Adds a product documents element to WooCommerce product pages + +== Description == + +The WooCommerce Product Documents plugin allows you to easily add documents to +your products and display them anywhere on the frontend. Documents can be +displayed on the product page, or anywhere on your site by using the +[woocommerce_product_documents] shortcode, or WooCommerce Product Documents +widget. This plugin is ideal for adding technical specifications or product +datasheets or brochures to your product catalog. + +Documents are organized into named sections which are rendered on the frontend +as a collapsible accordion. The plugin is built with a flexible and pluggable +architecture so with a minimum of effort and some knowledge of coding, the +frontend document display can be tweaked or completely replaced, allowing you +to create a unique layout with a minimum of effort. + +See https://docs.woocommerce.com/document/woocommerce-product-documents/ for full documentation. + +== Installation == + +1. Upload the entire 'woocommerce-product-documents' folder to the '/wp-content/plugins/' directory +2. Activate the plugin through the 'Plugins' menu in WordPress diff --git a/src/Lifecycle.php b/src/Lifecycle.php new file mode 100644 index 0000000..f75fe2c --- /dev/null +++ b/src/Lifecycle.php @@ -0,0 +1,63 @@ +get_admin_instance(); + + if ( ! $admin instanceof \WC_Product_Documents_Admin ) { + $admin = $this->get_plugin()->load_class( '/src/admin/class-wc-product-documents-admin.php', 'WC_Product_Documents_Admin' ); + } + + foreach ( $admin->get_global_settings() as $setting ) { + + if ( isset( $setting['id'], $setting['default'] ) ) { + + update_option( $setting['id'], $setting['default'] ); + } + } + } + + +} diff --git a/src/admin/class-wc-product-documents-admin.php b/src/admin/class-wc-product-documents-admin.php new file mode 100644 index 0000000..6d08ad9 --- /dev/null +++ b/src/admin/class-wc-product-documents-admin.php @@ -0,0 +1,445 @@ + Catalog page, immediately after the 'Product Data' section. + * + * @internal + * + * @since 1.0.0 + * + * @param array $settings associative array of WooCommerce settings + * @return array associative array of WooCommerce settings + */ + public function add_global_settings( $settings ) { + + $updated_settings = array(); + + foreach ( $settings as $setting ) { + + $updated_settings[] = $setting; + + if ( isset( $setting['id'], $setting['type'] ) + && 'catalog_options' === $setting['id'] + && 'sectionend' === $setting['type'] ) { + + $updated_settings = array_merge( $updated_settings, $this->get_global_settings() ); + } + } + + return $updated_settings; + } + + + /** + * Returns the global settings array for the plugin. + * + * @since 1.0 + * + * @return array the global settings + */ + public function get_global_settings() { + + return apply_filters( 'wc_product_documents_settings', array( + + // section start + array( + 'name' => __( 'Product Documents', 'woocommerce-product-documents' ), + 'type' => 'title', + 'desc' => '', + 'id' => 'wc_product_documents_catalog_options', + ), + + // documents title text + array( + 'title' => __( 'Product Documents Default Title', 'woocommerce-product-documents' ), + 'desc_tip' => __( 'This text will be shown above the product documents section unless overridden at the product level.', 'woocommerce-product-documents' ), + 'id' => 'wc_product_documents_title', + 'css' => 'width:200px;', + 'default' => __( 'Product Documents', 'woocommerce-product-documents' ), + 'type' => 'text', + ), + + // section end + array( + 'type' => 'sectionend', + 'id' => 'wc_product_documents_catalog_options' + ), + + ) ); + } + + + /** + * Loads admin scripts and styles. + * + * @internal + * + * @since 1.0 + * + * @param string $hook_suffix the current URL filename, ie edit.php, post.php, etc + */ + public function load_styles_scripts( $hook_suffix ) { + global $post_type; + + // load admin css/js only on edit product/new product pages + if ( 'product' === $post_type && ( 'post.php' === $hook_suffix || 'post-new.php' === $hook_suffix ) ) { + + // requires image upload capability + wp_enqueue_media(); + + // admin CSS + wp_enqueue_style( 'wc-product-documents-admin', wc_product_documents()->get_plugin_url() . '/assets/css/admin/wc-product-documents.min.css', array( 'woocommerce_admin_styles' ), \WC_Product_Documents::VERSION ); + + // admin JS + wp_enqueue_script( 'wc-product-documents-admin', wc_product_documents()->get_plugin_url() . '/assets/js/admin/wc-product-documents.min.js', \WC_Product_Documents::VERSION ); + + wp_enqueue_script( 'jquery-ui-sortable' ); + + // add script data + $new_section = $this->document_section_markup( new \WC_Product_Documents_Section(), '{index}' ); + $new_document = $this->document_markup( new \WC_Product_Documents_Document(), '{index}', '{sub_index}' ); + + $wc_product_documents_admin_params = array( + 'new_section' => str_replace( array( "\n", "\t" ), '', $new_section ), // cleanup the markup a bit + 'new_document' => str_replace( array( "\n", "\t" ), '', $new_document ), + 'confirm_remove_section_text' => __( 'Are you sure you want to remove this section?', 'woocommerce-product-documents' ), + 'confirm_remove_document_text' => __( 'Are you sure you want to remove this document?', 'woocommerce-product-documents' ), + 'select_file_text' => __( 'Select a File', 'woocommerce-product-documents' ), + 'set_file_text' => __( 'Set File', 'woocommerce-product-documents' ), + ); + + wp_localize_script( 'wc-product-documents-admin', 'wc_product_documents_admin_params', $wc_product_documents_admin_params ); + } + } + + + /** + * Adds 'Product Documents' tab to product data writepanel. + * + * @internal + * + * @since 1.0 + * + * @param array $tabs tab data + * @return void|array + */ + public function add_product_tab( $tabs = [] ) { + + if ( 'woocommerce_product_write_panel_tabs' === current_action() ) : + + ?> +
  • + +
  • + __( 'Product Documents', 'woocommerce-product-documents' ), + 'target' => 'wc-product-documents-data', + 'priority' => 900, + ]; + + return $tabs; + + endif; + } + + + /** + * Adds product documents options to product writepanel. + * + * @internal + * + * @since 1.0 + */ + public function add_product_tab_options() { + global $post; + + $documents = new \WC_Product_Documents_Collection( $post->ID ); + + ?> +
    + '_wc_product_documents_title', + 'label' => __( 'Product Documents Title', 'woocommerce-product-documents' ), + 'description' => __( 'This text optional will be shown as the title for the product documents element.', 'woocommerce-product-documents' ), + 'desc_tip' => true, + 'value' => wc_product_documents()->get_documents_title_text( $post->ID ), + ) + ); + + // show documents element on product page + woocommerce_wp_checkbox( + array( + 'id' => '_wc_product_documents_display', + 'label' => __( 'Show Product Documents', 'woocommerce-product-documents' ), + 'description' => __( 'Enable this to automatically display any documents for this product on the product page. Product documents can also be displayed anywhere via the widget or shortcode.', 'woocommerce-product-documents' ), + 'default' => 'yes', + ) + ); + + ?> +
    + +
    + + +
    + +
    + + get_sections( true ) as $index => $section ) : ?> + document_section_markup( $section, $index ); ?> + +
    + +
    + +
    + +
    + +
    + +
    + +

    + +
    + + is_default() ); ?> id="product_documents_default_section_" class="product-documents-default-section" name="product_documents_default_section" value="" /> + + +

    + +
    + + + + + + + + + + + + + + + get_documents( true ) as $sub_index => $document ) : ?> + document_markup( $document, $index, $sub_index ); ?> + + + + + + + + + +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + update_meta_data( '_wc_product_documents_title', $_POST['_wc_product_documents_title'] ); + } + + // render product documents on product page by default? + $documents_display = isset( $_POST['_wc_product_documents_display'] ) && 'yes' === $_POST['_wc_product_documents_display'] ? 'yes' : 'no'; + + $product->update_meta_data( '_wc_product_documents_display', $documents_display ); + + // then take care of any documents: + $documents_collection = new \WC_Product_Documents_Collection(); + $default_section = isset( $_POST['product_documents_default_section'] ) ? (int) $_POST['product_documents_default_section'] : 0; + $section_position = $_POST['product_documents_section_position']; + + if ( ! empty( $section_position ) && is_array( $section_position ) ) { + + foreach ( $section_position as $index => $position ) { + + // create the section object + $section_name = $_POST['product_documents_section_name'][ $index ]; + $section = new \WC_Product_Documents_Section( $section_name, (int) $index === $default_section ); + $documents = isset( $_POST['wc_product_document_position'][ $index ] ) ? $_POST['wc_product_document_position'][ $index ] : null; + + if ( ! empty( $documents ) && is_array( $documents ) ) { + + foreach ( $documents as $sub_index => $document_position ) { + + $document_label = $_POST['wc_product_document_label'][ $index ][ $sub_index ]; + $document_file = $_POST['wc_product_document_file_location'][ $index ][ $sub_index ]; + + // add the document object at the correct location + $section->add_document( new \WC_Product_Documents_Document( $document_label, $document_file ), $document_position ); + } + } + + // add the document section at the correct position + $documents_collection->add_section( $section, $position ); + } + } + + // persist the documents to the product + $documents_collection->save_to_product( $product_id, $product ); + + $product->save_meta_data(); + } + + +} diff --git a/src/class-wc-product-documents-collection.php b/src/class-wc-product-documents-collection.php new file mode 100644 index 0000000..bdddf7f --- /dev/null +++ b/src/class-wc-product-documents-collection.php @@ -0,0 +1,432 @@ +sections = array(); + + // load any persisted documents from the provided product + if ( $product_id ) { + $this->load_from_product( $product_id ); + } + } + + + /** + * Adds the given section to the collection of documents + * + * @since 1.0 + * @param \WC_Product_Documents_Section $section a section of documents + * @param int $index optional index at which to set the section, defaults to the final position + */ + public function add_section( $section, $index = null ) { + + if ( ! is_null( $index ) ) { + $this->sections[ $index ] = $section; + } else { + $this->sections[] = $section; + } + } + + + /** + * Returns the document sections + * + * @since 1.0 + * @param boolean $include_empty true to include empty sections, false otherwise. Defaults to false + * @return \WC_Product_Documents_Section[] Array of WC_Product_Documents_Section section objects + */ + public function get_sections( $include_empty = false ) { + + $sections = array(); + + if ( $include_empty ) { + + $sections = $this->sections; + + } else { + + // filter out empty sections (those without at least one document with a configured file location) + foreach ( $this->sections as $section ) { + + // add non-empty sections + if ( $section->has_documents( false ) ) { + $sections[] = $section; + } + } + } + + return apply_filters( 'wc_product_documents_get_sections', $sections, $this, $include_empty ); + } + + + /** + * Returns true if there is one or more sections in this collection + * + * @since 1.0 + * @param boolean $include_empty true to include empty sections, false otherwise. Defaults to false + * @return boolean true if there are any sections with documents, false otherwise + */ + public function has_sections( $include_empty = false ) { + + $sections = $this->get_sections( $include_empty ); + + // no sections with configured documents + return ! empty( $sections ); + } + + + /** + * Returns the index of the section marked as default, if any + * + * @since 1.0 + * @param boolean $include_empty use true to include empty sections, false otherwise. Defaults to false + * @return mixed index of default section, if any, otherwise false + */ + public function get_default_section_index( $include_empty = false ) { + + foreach ( $this->get_sections( $include_empty ) as $index => $section ) { + + if ( $section->is_default() ) { + return $index; + } + } + + // no default section found + return false; + } + + + /** + * Loads any configured sections and documents from the identified product + * + * @since 1.0 + * @param int $product_id product identifier + */ + private function load_from_product( $product_id ) { + + $this->sections = array(); + $this->product_id = $product_id; + $product = $product_id > 0 ? wc_get_product( $product_id ) : null; + $product_documents = $product ? $product->get_meta( '_wc_product_documents' ) : null; + + if ( is_array( $product_documents ) ) { + + foreach ( $product_documents as $section ) { + + $documents = array(); + + // create the set of documents + foreach ( $section['documents'] as $document ) { + $documents[] = new WC_Product_Documents_Document( $document['label'], $document['file_location'] ); + } + + // add the section + $this->add_section( new WC_Product_Documents_Section( $section['name'], $section['default'], $documents ) ); + } + } + } + + + /** + * Persists the product documents collection to the identified product. + * + * @since 1.0 + * + * @param int $product_id The product identifier + * @param \WC_Product $product The product object + */ + public function save_to_product( $product_id, $product = null ) { + + $product = ! $product instanceof \WC_Product ? wc_get_product( $product_id ) : $product; + $product_documents = array(); + + foreach ( $this->get_sections( true ) as $section ) { + + $documents = array(); + + foreach ( $section->get_documents( true ) as $document ) { + $documents[] = array( 'label' => $document->get_label( true ), 'file_location' => $document->get_file_location() ); + } + + $product_documents[] = array( 'name' => $section->get_name(), 'default' => $section->is_default(), 'documents' => $documents ); + } + + $product->update_meta_data( '_wc_product_documents', $product_documents ); + $product->save_meta_data(); + } + + + /** + * Returns the product id that these documents are a part of, if any + * + * @since 1.1.1 + * @return int product id or null + */ + public function get_product_id() { + return $this->product_id; + } + + +} // end \WC_Product_Documents_Collection class + + +/** + * Product Documents Section class. + * This represents a set of product documents. + * + * @since 1.0 + */ +class WC_Product_Documents_Section { + + /** @var string Section name */ + private $name; + + /** @var bool true if this section is the default one */ + private $is_default; + + /** @var \WC_Product_Documents_Document[] array Array of WC_Product_Documents_Document objects */ + private $documents; + + + /** + * Initializes a set of product documents. + * + * @since 1.0 + * + * @param string $name optional section name, defaults to empty string + * @param boolean $is_default true if this section is the default one, optional defaults to false + * @param \WC_Product_Documents_Document[] $documents optional array of WC_Product_Documents_Document document objects, defaults to empty array + */ + public function __construct( $name = '', $is_default = false, $documents = array() ) { + + $this->name = $name; + $this->is_default = $is_default; + $this->documents = $documents; + } + + + /** + * Adds the given document to the collection of documents for this section. + * + * @since 1.0 + * + * @param \WC_Product_Documents_Document $document a document + * @param int $index optional index at which to set the document, defaults to the final position + */ + public function add_document( $document, $index = null ) { + + if ( ! is_null( $index ) ) { + $this->documents[ $index ] = $document; + } else { + $this->documents[] = $document; + } + } + + + /** + * Returns the section name. + * + * @since 1.0 + * + * @return string section name, or null + */ + public function get_name() { + + return is_string( $this->name ) ? stripslashes( $this->name ) : $this->name; + } + + + /** + * Returns true if this is the default section. + * + * @since 1.0 + * + * @return bool + */ + public function is_default() { + + return $this->is_default; + } + + + /** + * Returns the documents for this section. + * + * @since 1.0 + * + * @param bool $include_empty true to include empty documents, false otherwise. Defaults to false + * @return \WC_Product_Documents_Document[] array of WC_Product_Documents_Document document objects + */ + public function get_documents( $include_empty = false ) { + + if ( $include_empty ) { + + // return all documents, including those that may be empty + return $this->documents; + + } else { + + // filter out empty documents (those without a configured file location) + $documents = array(); + + foreach ( $this->documents as $document ) { + + // add the document if not empty + if ( ! $document->is_empty() ) { + $documents[] = $document; + } + } + + return $documents; + } + } + + + /** + * Returns true if this section has any documents. + * + * @since 1.0 + * + * @param bool $include_empty true to include empty documents, false otherwise. Defaults to false + * @return bool + */ + public function has_documents( $include_empty = false ) { + + $documents = $this->get_documents( $include_empty ); + + return ! empty( $documents ); + } + + +} // end \WC_Product_Documents_Section class + + +/** + * Product Document class, represents a document. + * + * @since 1.0 + */ +class WC_Product_Documents_Document { + + + /** @var string document label */ + private $label; + + /** @var string the URL or path to the document file */ + private $file_location; + + + /** + * Initializes a product document. + * + * @since 1.0 + * + * @param string $label optional document label, defaults to empty string + * @param string $file_location optional URL or path to the document file, defaults to empty string + */ + public function __construct( $label = '', $file_location = '' ) { + + $this->label = $label; + $this->file_location = $file_location; + } + + + /** + * Returns the displayable file label, or the filename otherwise. + * + * @since 1.0 + * + * @param bool $raw true will return the raw label value, false returns the display value. defaults to false + * @return string the displayable file label, or null + */ + public function get_label( $raw = false ) { + + // use display label if set + if ( $this->label || $raw ) { + $label = $this->label; + // otherwise default to file name + } elseif ( $this->file_location ) { + $label = basename( $this->file_location ); + } else { + $label = null; + } + + return is_string( $label ) ? stripslashes( $label ) : null; + } + + + /** + * Returns the URL or path to the document file. + * + * @since 1.0 + * + * @return string the URL or path to the document file, or null + */ + public function get_file_location() { + + return $this->file_location; + } + + + /** + * Returns true if this document is not fully configured (has no file location). + * + * @since 1.0 + * + * @return bool true if this document is empty + */ + public function is_empty() { + + $file_location = $this->get_file_location(); + + return empty( $file_location ); + } + + +} // end \WC_Product_Documents_Document class diff --git a/src/shortcodes/class-wc-product-documents-shortcode-list.php b/src/shortcodes/class-wc-product-documents-shortcode-list.php new file mode 100644 index 0000000..d4b28a0 --- /dev/null +++ b/src/shortcodes/class-wc-product-documents-shortcode-list.php @@ -0,0 +1,122 @@ + 'title', + 'order' => 'ASC' + ), $atts ); + + $query_args = array( + 'post_type' => 'product', + 'post_status' => 'publish', + 'ignore_sticky_posts' => 1, + 'orderby' => $atts['orderby'], + 'order' => $atts['order'], + 'posts_per_page' => -1, + ); + + $query_args['tax_query'] = array( + array( + 'taxonomy' => 'product_visibility', + 'field' => 'name', + 'operator' => 'NOT IN', + 'terms' => array( + 'exclude-from-search', + 'exclude-from-catalog', + 'outofstock', + ), + ), + ); + + $query_args = apply_filters( 'wc_product_documents_list_shortcode_query_args', $query_args ); + $products = get_posts( $query_args ); + + foreach ( $products as $post ) { + + if ( $product = wc_get_product( $post ) ) { + + // bail if the product is not accessible for the current user + if ( ! wc_product_documents()->is_product_accessible( $product ) ) { + continue; + } + + $product_documents = $product->get_meta( '_wc_product_documents' ); + + if ( ! empty( $product_documents ) ) { + + // Get the title + $title = get_the_title( $post->ID ); + + // Render any product documents + woocommerce_product_documents_template( $product, $title ); + } + } + } + } + + +} diff --git a/src/shortcodes/class-wc-product-documents-shortcode.php b/src/shortcodes/class-wc-product-documents-shortcode.php new file mode 100644 index 0000000..bb216c7 --- /dev/null +++ b/src/shortcodes/class-wc-product-documents-shortcode.php @@ -0,0 +1,108 @@ + '', + 'product_sku' => '', + 'title' => '', + ), $atts ); + + // product by sku? + if ( $atts['product_sku'] ) { + $atts['product_id'] = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_sku' AND meta_value = %s LIMIT 1", $atts['product_sku'] ) ); + } + + + // product by id? + if ( $atts['product_id'] ) { + $product = wc_get_product( $atts['product_id'] ); + } + + // if we don't have a product by now either none was specified, or the current page didn't have a default product (global $product above) + if ( ! $product ) { + return; + } + + // bail if the product isn't readable by the current user + if ( ! wc_product_documents()->is_product_accessible( $product ) ) { + return; + } + + // default title? + if ( ! $atts['title'] ) { + $atts['title'] = wc_product_documents()->get_documents_title_text( $product->get_id() ); + } + + // Render any product documents + woocommerce_product_documents_template( $product, $atts['title'] ); + } + + +} diff --git a/src/wc-product-documents-template.php b/src/wc-product-documents-template.php new file mode 100755 index 0000000..0af818f --- /dev/null +++ b/src/wc-product-documents-template.php @@ -0,0 +1,129 @@ +get_id() ); + + if ( ! $documents_collection->has_sections() ) { + return; + } + + // enqueue the required JavaScript + woocommerce_product_documents_scripts_template(); + + // get the default index (if any) + $active_index = $documents_collection->get_default_section_index(); + + if ( false === $active_index ) { + $active_index = 'false'; + } + + // javascript to activate the accordion element + ob_start(); + + ?> + $( '.woocommerce-product-documents-get_id() ?>' ).accordion( { + heightStyle: "content", // each panel will only be as tall as its content + collapsible: true, // all panels can be collapsed at once + active: // the active panel (if any) + } ); + $title, + 'product' => $product, + 'product_id' => $product->get_id(), + 'documents_collection' => $documents_collection, + ), + '', + wc_product_documents()->get_plugin_path() . '/templates/' + ); + } + +} + + +if ( ! function_exists( 'woocommerce_product_documents_scripts_template' ) ) { + + + /** + * Enqueue required scripts/styles: + * + * + jQuery UI Accordion + * + Product Documents frontend styling + * + jQuery UI Smoothness CSS + * + * @since 1.0 + */ + function woocommerce_product_documents_scripts_template() { + global $wp_scripts; + + // enqueue the jquery accordion script + wp_enqueue_script( 'jquery-ui-accordion' ); + + // enqueue the frontend styles + wp_enqueue_style( 'wc-product-documents', wc_product_documents()->get_plugin_url() . '/assets/css/frontend/wc-product-documents.min.css', false, \WC_Product_Documents::VERSION ); + + // get jQuery UI version + $jquery_version = isset( $wp_scripts->registered['jquery-ui-core']->ver ) ? $wp_scripts->registered['jquery-ui-core']->ver : '1.9.2'; + + // enqueue UI CSS + wp_enqueue_style( 'jquery-ui-style', '//ajax.googleapis.com/ajax/libs/jqueryui/' . $jquery_version . '/themes/smoothness/jquery-ui.css' ); + } + + +} diff --git a/src/widgets/class-wc-product-documents-widget-documents.php b/src/widgets/class-wc-product-documents-widget-documents.php new file mode 100644 index 0000000..0b1f2a6 --- /dev/null +++ b/src/widgets/class-wc-product-documents-widget-documents.php @@ -0,0 +1,137 @@ + 'widget_wc_product_documents', + 'description' => __( 'Display a set of product documents for the current product if on a product page.', 'woocommerce-product-documents' ), + ); + + // instantiate the widget + parent::__construct( 'wc_product_documents_widget_documents', __( 'WooCommerce Product Documents', 'woocommerce-product-documents' ), $options ); + } + + + /** + * Renders the product documents widget. + * + * @since 1.0 + * + * @see \WP_Widget::widget() + * + * @param array $args widget arguments + * @param array $instance saved values from database + */ + public function widget( $args, $instance ) { + + // technically this widget will render anytime there's a global $product available, not just on the product page, which may cause issues, but is kind of handy as well + global $product; + + // bail if no product available + if ( ! $product ) { + return; + } + + $documents_collection = new WC_Product_Documents_Collection( $product->get_id() ); + if ( ! $documents_collection->has_sections() ) { + return; + } + + // get the widget configuration + $title = $instance['title']; + + // default to product documents title from product configuration. Granted this makes it more difficult to have no title in the widget area, but is that an issue? + if ( ! $title ) { + $title = wc_product_documents()->get_documents_title_text( $product->get_id() ); + } + + echo $args['before_widget']; + + if ( $title ) { + echo $args['before_title'] . $title . $args['after_title']; + } + + woocommerce_product_documents_template( $product, false ); // false to force the template to not display a title since the widget takes care of it + + echo $args['after_widget']; + } + + + /** + * Updates the widget title & selected product. + * + * @since 1.0 + * + * @see \WP_Widget::update() + * + * @param array $new_instance new widget settings + * @param array $old_instance old widget settings + * @return array updated widget settings + */ + public function update( $new_instance, $old_instance ) { + + $instance['title'] = strip_tags( $new_instance['title'] ); + + return $instance; + } + + + /** + * Renders the admin form for the widget. + * + * @since 1.0 + * + * @param array $instance the widget settings + * @return string|void + */ + public function form( $instance ) { + + ?> +

    + + +

    + ' . esc_html( $title ) . '', $title, $product ); +} + +?> +
    + + get_sections() as $section ) : ?> + +

    get_name(); ?>

    + +
    + +
    + + + +
    diff --git a/vendor/skyverge/wc-plugin-framework/license.txt b/vendor/skyverge/wc-plugin-framework/license.txt new file mode 100644 index 0000000..c30c0d8 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/license.txt @@ -0,0 +1,694 @@ +WooCommerce Plugin Framework + +Copyright 2013-2023, SkyVerge, Inc. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright © 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 +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 +software for all its users. We, the Free Software Foundation, use the +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 +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 +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 +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: +(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 +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 +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 +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +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. +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 +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "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 +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 +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 +on the Program. + + 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 +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" +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 +extent that warranties are provided), that licensees may convey the +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. + + 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 +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 +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 +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(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 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 +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +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 +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + 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 +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 +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 +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +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 +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + 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 +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 +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. + + 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 +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, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + 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. + + 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. + + 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 +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 +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +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. + + 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. + + 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. + + 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. + + 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 +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, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +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, +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 +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 +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 +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +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 +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 +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, +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. + + "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 +that they are valid under applicable law. If additional permissions +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 +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 +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 + + 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 + + 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 + + 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 +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 +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +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 +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 +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + 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 +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 +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 +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. + + 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, +nothing other than this License grants you permission to propagate or +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. + + 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 +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 +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +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 +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 +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + 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 +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, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +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 +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 +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, +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, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +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 +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 +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 +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 +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +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 +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. + + 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 +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +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. + + 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 +License will continue to apply to the part which is the covered work, +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. + + 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 +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 +version or of any later version published by the Free Software +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 +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 +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. + + 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, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +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. + + 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 +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +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. + + 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 + + How to Apply These Terms to Your New Programs + + 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 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 © + + 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. + + 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 +notice like this when it starts in an interactive mode: + + Copyright © + 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, +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 +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 +Public License instead of this License. But first, please read +. diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Address.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Address.php new file mode 100644 index 0000000..ceabfb8 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Address.php @@ -0,0 +1,292 @@ +line_1; + } + + + /** + * Gets line 2 of the street address. + * + * @since 5.3.0 + * + * @return string + */ + public function get_line_2() { + + return $this->line_2; + } + + + /** + * Gets line 3 of the street address. + * + * @since 5.3.0 + * + * @return string + */ + public function get_line_3() { + + return $this->line_3; + } + + + /** + * Gets the locality or city. + * + * @since 5.3.0 + * + * @return string + */ + public function get_locality() { + + return $this->locality; + } + + + /** + * Gets the region or state. + * + * @since 5.3.0 + * + * @return string + */ + public function get_region() { + + return $this->region; + } + + + /** + * Gets the country. + * + * @since 5.3.0 + * + * @return string + */ + public function get_country() { + + return $this->country; + } + + + /** + * Gets the postcode. + * + * @since 5.3.0 + * + * @return string + */ + public function get_postcode() { + + return $this->postcode; + } + + + /** + * Gets the hash representation of this address. + * + * @see Address::get_hash_data() + * + * @since 5.3.0 + * + * @return string + */ + public function get_hash() { + + return md5( json_encode( $this->get_hash_data() ) ); + } + + + /** + * Gets the data used to generate a hash for the address. + * + * @since 5.3.0 + * + * @return string[] + */ + protected function get_hash_data() { + + return [ + $this->get_line_1(), + $this->get_line_2(), + $this->get_line_3(), + $this->get_locality(), + $this->get_region(), + $this->get_country(), + $this->get_postcode(), + ]; + } + + + /** Setter methods ************************************************************************************************/ + + + /** + * Sets line 1 of the street address. + * + * @since 5.3.0 + * + * @param string $value line 1 value + */ + public function set_line_1( $value ) { + + $this->line_1 = $value; + } + + + /** + * Sets line 2 of the street address. + * + * @since 5.3.0 + * + * @param string $value line 2 value + */ + public function set_line_2( $value ) { + + $this->line_2 = $value; + } + + + /** + * Gets line 3 of the street address. + * + * @since 5.3.0 + * + * @param string $value line 3 value + */ + public function set_line_3( $value ) { + + $this->line_3 = $value; + } + + + /** + * Gets the locality or city. + * + * @since 5.3.0 + * + * @param string $value locality value + */ + public function set_locality( $value ) { + + $this->locality = $value; + } + + + /** + * Gets the region or state. + * + * @since 5.3.0 + * + * @param string $value region value + */ + public function set_region( $value ) { + + $this->region = $value; + } + + + /** + * Sets the country. + * + * @since 5.3.0 + * + * @param string $value country value + */ + public function set_country( $value ) { + + $this->country = $value; + } + + + /** + * Sets the postcode. + * + * @since 5.3.0 + * + * @param string $value postcode value + */ + public function set_postcode( $value ) { + + $this->postcode = $value; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Customer_Address.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Customer_Address.php new file mode 100644 index 0000000..5cdc78c --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Addresses/Customer_Address.php @@ -0,0 +1,150 @@ +first_name; + } + + + /** + * Gets the customer first name. + * + * @since 5.3.0 + * + * @return string + */ + public function get_last_name() { + + return $this->last_name; + } + + + /** + * Gets the data used to generate a hash for the address. + * + * @see Address::get_hash_data() + * + * @since 5.3.0 + * + * @return string[] + */ + protected function get_hash_data() { + + // add the first & last name to data used to generate the hash + return array_merge( [ + $this->get_first_name(), + $this->get_last_name(), + ], parent::get_hash_data() ); + } + + + /** Setter Methods ************************************************************************************************/ + + + /** + * Sets the customer first name. + * + * @since 5.3.0 + * + * @param string $value first name value + */ + public function set_first_name( $value ) { + + $this->first_name = $value; + } + + + /** + * Sets the customer last name. + * + * @since 5.3.0 + * + * @param string $value first name value + */ + public function set_last_name( $value ) { + + $this->last_name = $value; + } + + + /** + * Sets the full address based on a WooCommerce order. + * + * @since 5.3.0 + * + * @param \WC_Order $order WooCommerce order object + * @param string $type address type, like billing or shipping + */ + public function set_from_order( \WC_Order $order, $type = 'billing' ) { + + $this->set_first_name( $order->{"get_{$type}_first_name"}() ); + $this->set_last_name( $order->{"get_{$type}_last_name"}() ); + $this->set_line_1( $order->{"get_{$type}_address_1"}() ); + $this->set_line_2( $order->{"get_{$type}_address_2"}() ); + $this->set_locality( $order->{"get_{$type}_city"}() ); + $this->set_region( $order->{"get_{$type}_state"}() ); + $this->set_country( $order->{"get_{$type}_country"}() ); + $this->set_postcode( $order->{"get_{$type}_postcode"}() ); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Country_Helper.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Country_Helper.php new file mode 100644 index 0000000..fa3fbae --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Country_Helper.php @@ -0,0 +1,661 @@ + ISO 3166-alpha3 */ + static public $alpha3 = [ + 'AF' => 'AFG', 'AL' => 'ALB', 'DZ' => 'DZA', 'AD' => 'AND', 'AO' => 'AGO', + 'AG' => 'ATG', 'AR' => 'ARG', 'AM' => 'ARM', 'AU' => 'AUS', 'AT' => 'AUT', + 'AZ' => 'AZE', 'BS' => 'BHS', 'BH' => 'BHR', 'BD' => 'BGD', 'BB' => 'BRB', + 'BY' => 'BLR', 'BE' => 'BEL', 'BZ' => 'BLZ', 'BJ' => 'BEN', 'BT' => 'BTN', + 'BO' => 'BOL', 'BA' => 'BIH', 'BW' => 'BWA', 'BR' => 'BRA', 'BN' => 'BRN', + 'BG' => 'BGR', 'BF' => 'BFA', 'BI' => 'BDI', 'KH' => 'KHM', 'CM' => 'CMR', + 'CA' => 'CAN', 'CV' => 'CPV', 'CF' => 'CAF', 'TD' => 'TCD', 'CL' => 'CHL', + 'CN' => 'CHN', 'CO' => 'COL', 'KM' => 'COM', 'CD' => 'COD', 'CG' => 'COG', + 'CR' => 'CRI', 'CI' => 'CIV', 'HR' => 'HRV', 'CU' => 'CUB', 'CY' => 'CYP', + 'CZ' => 'CZE', 'DK' => 'DNK', 'DJ' => 'DJI', 'DM' => 'DMA', 'DO' => 'DOM', + 'EC' => 'ECU', 'EG' => 'EGY', 'SV' => 'SLV', 'GQ' => 'GNQ', 'ER' => 'ERI', + 'EE' => 'EST', 'ET' => 'ETH', 'FJ' => 'FJI', 'FI' => 'FIN', 'FR' => 'FRA', + 'GA' => 'GAB', 'GM' => 'GMB', 'GE' => 'GEO', 'DE' => 'DEU', 'GH' => 'GHA', + 'GR' => 'GRC', 'GD' => 'GRD', 'GT' => 'GTM', 'GN' => 'GIN', 'GW' => 'GNB', + 'GY' => 'GUY', 'HT' => 'HTI', 'HN' => 'HND', 'HU' => 'HUN', 'IS' => 'ISL', + 'IN' => 'IND', 'ID' => 'IDN', 'IR' => 'IRN', 'IQ' => 'IRQ', 'IE' => 'IRL', + 'IL' => 'ISR', 'IT' => 'ITA', 'JM' => 'JAM', 'JP' => 'JPN', 'JO' => 'JOR', + 'KZ' => 'KAZ', 'KE' => 'KEN', 'KI' => 'KIR', 'KP' => 'PRK', 'KR' => 'KOR', + 'KW' => 'KWT', 'KG' => 'KGZ', 'LA' => 'LAO', 'LV' => 'LVA', 'LB' => 'LBN', + 'LS' => 'LSO', 'LR' => 'LBR', 'LY' => 'LBY', 'LI' => 'LIE', 'LT' => 'LTU', + 'LU' => 'LUX', 'MK' => 'MKD', 'MG' => 'MDG', 'MW' => 'MWI', 'MY' => 'MYS', + 'MV' => 'MDV', 'ML' => 'MLI', 'MT' => 'MLT', 'MH' => 'MHL', 'MR' => 'MRT', + 'MU' => 'MUS', 'MX' => 'MEX', 'FM' => 'FSM', 'MD' => 'MDA', 'MC' => 'MCO', + 'MN' => 'MNG', 'ME' => 'MNE', 'MA' => 'MAR', 'MZ' => 'MOZ', 'MM' => 'MMR', + 'NA' => 'NAM', 'NR' => 'NRU', 'NP' => 'NPL', 'NL' => 'NLD', 'NZ' => 'NZL', + 'NI' => 'NIC', 'NE' => 'NER', 'NG' => 'NGA', 'NO' => 'NOR', 'OM' => 'OMN', + 'PK' => 'PAK', 'PW' => 'PLW', 'PA' => 'PAN', 'PG' => 'PNG', 'PY' => 'PRY', + 'PE' => 'PER', 'PH' => 'PHL', 'PL' => 'POL', 'PT' => 'PRT', 'QA' => 'QAT', + 'RO' => 'ROU', 'RU' => 'RUS', 'RW' => 'RWA', 'KN' => 'KNA', 'LC' => 'LCA', + 'VC' => 'VCT', 'WS' => 'WSM', 'SM' => 'SMR', 'ST' => 'STP', 'SA' => 'SAU', + 'SN' => 'SEN', 'RS' => 'SRB', 'SC' => 'SYC', 'SL' => 'SLE', 'SG' => 'SGP', + 'SK' => 'SVK', 'SI' => 'SVN', 'SB' => 'SLB', 'SO' => 'SOM', 'ZA' => 'ZAF', + 'ES' => 'ESP', 'LK' => 'LKA', 'SD' => 'SDN', 'SR' => 'SUR', 'SZ' => 'SWZ', + 'SE' => 'SWE', 'CH' => 'CHE', 'SY' => 'SYR', 'TJ' => 'TJK', 'TZ' => 'TZA', + 'TH' => 'THA', 'TL' => 'TLS', 'TG' => 'TGO', 'TO' => 'TON', 'TT' => 'TTO', + 'TN' => 'TUN', 'TR' => 'TUR', 'TM' => 'TKM', 'TV' => 'TUV', 'UG' => 'UGA', + 'UA' => 'UKR', 'AE' => 'ARE', 'GB' => 'GBR', 'US' => 'USA', 'UY' => 'URY', + 'UZ' => 'UZB', 'VU' => 'VUT', 'VA' => 'VAT', 'VE' => 'VEN', 'VN' => 'VNM', + 'YE' => 'YEM', 'ZM' => 'ZMB', 'ZW' => 'ZWE', 'TW' => 'TWN', 'CX' => 'CXR', + 'CC' => 'CCK', 'HM' => 'HMD', 'NF' => 'NFK', 'NC' => 'NCL', 'PF' => 'PYF', + 'YT' => 'MYT', 'GP' => 'GLP', 'PM' => 'SPM', 'WF' => 'WLF', 'TF' => 'ATF', + 'BV' => 'BVT', 'CK' => 'COK', 'NU' => 'NIU', 'TK' => 'TKL', 'GG' => 'GGY', + 'IM' => 'IMN', 'JE' => 'JEY', 'AI' => 'AIA', 'BM' => 'BMU', 'IO' => 'IOT', + 'VG' => 'VGB', 'KY' => 'CYM', 'FK' => 'FLK', 'GI' => 'GIB', 'MS' => 'MSR', + 'PN' => 'PCN', 'SH' => 'SHN', 'GS' => 'SGS', 'TC' => 'TCA', 'MP' => 'MNP', + 'PR' => 'PRI', 'AS' => 'ASM', 'UM' => 'UMI', 'GU' => 'GUM', 'VI' => 'VIR', + 'HK' => 'HKG', 'MO' => 'MAC', 'FO' => 'FRO', 'GL' => 'GRL', 'GF' => 'GUF', + 'MQ' => 'MTQ', 'RE' => 'REU', 'AX' => 'ALA', 'AW' => 'ABW', 'AN' => 'ANT', + 'SJ' => 'SJM', 'AC' => 'ASC', 'TA' => 'TAA', 'AQ' => 'ATA', 'CW' => 'CUW', + ]; + + /** @var array ISO 3166-alpha2 => ISO 3166-numeric */ + static public $numeric = [ + 'AF' => '004', 'AX' => '248', 'AL' => '008', 'DZ' => '012', 'AS' => '016', + 'AD' => '020', 'AO' => '024', 'AI' => '660', 'AQ' => '010', 'AG' => '028', + 'AR' => '032', 'AM' => '051', 'AW' => '533', 'AU' => '036', 'AT' => '040', + 'AZ' => '031', 'BS' => '044', 'BH' => '048', 'BD' => '050', 'BB' => '052', + 'BY' => '112', 'BE' => '056', 'BZ' => '084', 'BJ' => '204', 'BM' => '060', + 'BT' => '064', 'BO' => '068', 'BQ' => '535', 'BA' => '070', 'BW' => '072', + 'BV' => '074', 'BR' => '076', 'IO' => '086', 'BN' => '096', 'BG' => '100', + 'BF' => '854', 'BI' => '108', 'KH' => '116', 'CM' => '120', 'CA' => '124', + 'CV' => '132', 'KY' => '136', 'CF' => '140', 'TD' => '148', 'CL' => '152', + 'CN' => '156', 'CX' => '162', 'CC' => '166', 'CO' => '170', 'KM' => '174', + 'CG' => '178', 'CD' => '180', 'CK' => '184', 'CR' => '188', 'CI' => '384', + 'HR' => '191', 'CU' => '192', 'CW' => '531', 'CY' => '196', 'CZ' => '203', + 'DK' => '208', 'DJ' => '262', 'DM' => '212', 'DO' => '214', 'EC' => '218', + 'EG' => '818', 'SV' => '222', 'GQ' => '226', 'ER' => '232', 'EE' => '233', + 'ET' => '231', 'FK' => '238', 'FO' => '234', 'FJ' => '242', 'FI' => '246', + 'FR' => '250', 'GF' => '254', 'PF' => '258', 'TF' => '260', 'GA' => '266', + 'GM' => '270', 'GE' => '268', 'DE' => '276', 'GH' => '288', 'GI' => '292', + 'GR' => '300', 'GL' => '304', 'GD' => '308', 'GP' => '312', 'GU' => '316', + 'GT' => '320', 'GG' => '831', 'GN' => '324', 'GW' => '624', 'GY' => '328', + 'HT' => '332', 'HM' => '334', 'VA' => '336', 'HN' => '340', 'HK' => '344', + 'HU' => '348', 'IS' => '352', 'IN' => '356', 'ID' => '360', 'IR' => '364', + 'IQ' => '368', 'IE' => '372', 'IM' => '833', 'IL' => '376', 'IT' => '380', + 'JM' => '388', 'JP' => '392', 'JE' => '832', 'JO' => '400', 'KZ' => '398', + 'KE' => '404', 'KI' => '296', 'KP' => '408', 'KR' => '410', 'KW' => '414', + 'KG' => '417', 'LA' => '418', 'LV' => '428', 'LB' => '422', 'LS' => '426', + 'LR' => '430', 'LY' => '434', 'LI' => '438', 'LT' => '440', 'LU' => '442', + 'MO' => '446', 'MK' => '807', 'MG' => '450', 'MW' => '454', 'MY' => '458', + 'MV' => '462', 'ML' => '466', 'MT' => '470', 'MH' => '584', 'MQ' => '474', + 'MR' => '478', 'MU' => '480', 'YT' => '175', 'MX' => '484', 'FM' => '583', + 'MD' => '498', 'MC' => '492', 'MN' => '496', 'ME' => '499', 'MS' => '500', + 'MA' => '504', 'MZ' => '508', 'MM' => '104', 'NA' => '516', 'NR' => '520', + 'NP' => '524', 'NL' => '528', 'NC' => '540', 'NZ' => '554', 'NI' => '558', + 'NE' => '562', 'NG' => '566', 'NU' => '570', 'NF' => '574', 'MP' => '580', + 'NO' => '578', 'OM' => '512', 'PK' => '586', 'PW' => '585', 'PS' => '275', + 'PA' => '591', 'PG' => '598', 'PY' => '600', 'PE' => '604', 'PH' => '608', + 'PN' => '612', 'PL' => '616', 'PT' => '620', 'PR' => '630', 'QA' => '634', + 'RE' => '638', 'RO' => '642', 'RU' => '643', 'RW' => '646', 'BL' => '652', + 'SH' => '654', 'KN' => '659', 'LC' => '662', 'MF' => '663', 'PM' => '666', + 'VC' => '670', 'WS' => '882', 'SM' => '674', 'ST' => '678', 'SA' => '682', + 'SN' => '686', 'RS' => '688', 'SC' => '690', 'SL' => '694', 'SG' => '702', + 'SX' => '534', 'SK' => '703', 'SI' => '705', 'SB' => '090', 'SO' => '706', + 'ZA' => '710', 'GS' => '239', 'SS' => '728', 'ES' => '724', 'LK' => '144', + 'SD' => '729', 'SR' => '740', 'SJ' => '744', 'SZ' => '748', 'SE' => '752', + 'CH' => '756', 'SY' => '760', 'TW' => '158', 'TJ' => '762', 'TZ' => '834', + 'TH' => '764', 'TL' => '626', 'TG' => '768', 'TK' => '772', 'TO' => '776', + 'TT' => '780', 'TN' => '788', 'TR' => '792', 'TM' => '795', 'TC' => '796', + 'TV' => '798', 'UG' => '800', 'UA' => '804', 'AE' => '784', 'GB' => '826', + 'US' => '840', 'UM' => '581', 'UY' => '858', 'UZ' => '860', 'VU' => '548', + 'VE' => '862', 'VN' => '704', 'VG' => '092', 'VI' => '850', 'WF' => '876', + 'EH' => '732', 'YE' => '887', 'ZM' => '894', 'ZW' => '716', + ]; + + /** @var array ISO 3166-alpha2 => phone calling code(s) */ + static public $calling_codes = [ + 'BD' => '+880', + 'BE' => '+32', + 'BF' => '+226', + 'BG' => '+359', + 'BA' => '+387', + 'BB' => '+1246', + 'WF' => '+681', + 'BL' => '+590', + 'BM' => '+1441', + 'BN' => '+673', + 'BO' => '+591', + 'BH' => '+973', + 'BI' => '+257', + 'BJ' => '+229', + 'BT' => '+975', + 'JM' => '+1876', + 'BV' => '', + 'BW' => '+267', + 'WS' => '+685', + 'BQ' => '+599', + 'BR' => '+55', + 'BS' => '+1242', + 'JE' => '+441534', + 'BY' => '+375', + 'BZ' => '+501', + 'RU' => '+7', + 'RW' => '+250', + 'RS' => '+381', + 'TL' => '+670', + 'RE' => '+262', + 'TM' => '+993', + 'TJ' => '+992', + 'RO' => '+40', + 'TK' => '+690', + 'GW' => '+245', + 'GU' => '+1671', + 'GT' => '+502', + 'GS' => '', + 'GR' => '+30', + 'GQ' => '+240', + 'GP' => '+590', + 'JP' => '+81', + 'GY' => '+592', + 'GG' => '+441481', + 'GF' => '+594', + 'GE' => '+995', + 'GD' => '+1473', + 'GB' => '+44', + 'GA' => '+241', + 'SV' => '+503', + 'GN' => '+224', + 'GM' => '+220', + 'GL' => '+299', + 'GI' => '+350', + 'GH' => '+233', + 'OM' => '+968', + 'TN' => '+216', + 'JO' => '+962', + 'HR' => '+385', + 'HT' => '+509', + 'HU' => '+36', + 'HK' => '+852', + 'HN' => '+504', + 'HM' => '', + 'VE' => '+58', + 'PR' => [ + '+1787', + '+1939', + ], + 'PS' => '+970', + 'PW' => '+680', + 'PT' => '+351', + 'SJ' => '+47', + 'PY' => '+595', + 'IQ' => '+964', + 'PA' => '+507', + 'PF' => '+689', + 'PG' => '+675', + 'PE' => '+51', + 'PK' => '+92', + 'PH' => '+63', + 'PN' => '+870', + 'PL' => '+48', + 'PM' => '+508', + 'ZM' => '+260', + 'EH' => '+212', + 'EE' => '+372', + 'EG' => '+20', + 'ZA' => '+27', + 'EC' => '+593', + 'IT' => '+39', + 'VN' => '+84', + 'SB' => '+677', + 'ET' => '+251', + 'SO' => '+252', + 'ZW' => '+263', + 'SA' => '+966', + 'ES' => '+34', + 'ER' => '+291', + 'ME' => '+382', + 'MD' => '+373', + 'MG' => '+261', + 'MF' => '+590', + 'MA' => '+212', + 'MC' => '+377', + 'UZ' => '+998', + 'MM' => '+95', + 'ML' => '+223', + 'MO' => '+853', + 'MN' => '+976', + 'MH' => '+692', + 'MK' => '+389', + 'MU' => '+230', + 'MT' => '+356', + 'MW' => '+265', + 'MV' => '+960', + 'MQ' => '+596', + 'MP' => '+1670', + 'MS' => '+1664', + 'MR' => '+222', + 'IM' => '+441624', + 'UG' => '+256', + 'TZ' => '+255', + 'MY' => '+60', + 'MX' => '+52', + 'IL' => '+972', + 'FR' => '+33', + 'IO' => '+246', + 'SH' => '+290', + 'FI' => '+358', + 'FJ' => '+679', + 'FK' => '+500', + 'FM' => '+691', + 'FO' => '+298', + 'NI' => '+505', + 'NL' => '+31', + 'NO' => '+47', + 'NA' => '+264', + 'VU' => '+678', + 'NC' => '+687', + 'NE' => '+227', + 'NF' => '+672', + 'NG' => '+234', + 'NZ' => '+64', + 'NP' => '+977', + 'NR' => '+674', + 'NU' => '+683', + 'CK' => '+682', + 'XK' => '', + 'CI' => '+225', + 'CH' => '+41', + 'CO' => '+57', + 'CN' => '+86', + 'CM' => '+237', + 'CL' => '+56', + 'CC' => '+61', + 'CA' => '+1', + 'CG' => '+242', + 'CF' => '+236', + 'CD' => '+243', + 'CZ' => '+420', + 'CY' => '+357', + 'CX' => '+61', + 'CR' => '+506', + 'CW' => '+599', + 'CV' => '+238', + 'CU' => '+53', + 'SZ' => '+268', + 'SY' => '+963', + 'SX' => '+599', + 'KG' => '+996', + 'KE' => '+254', + 'SS' => '+211', + 'SR' => '+597', + 'KI' => '+686', + 'KH' => '+855', + 'KN' => '+1869', + 'KM' => '+269', + 'ST' => '+239', + 'SK' => '+421', + 'KR' => '+82', + 'SI' => '+386', + 'KP' => '+850', + 'KW' => '+965', + 'SN' => '+221', + 'SM' => '+378', + 'SL' => '+232', + 'SC' => '+248', + 'KZ' => '+7', + 'KY' => '+1345', + 'SG' => '+65', + 'SE' => '+46', + 'SD' => '+249', + 'DO' => [ + '+1809', + '+1829', + '+1849', + ], + 'DM' => '+1767', + 'DJ' => '+253', + 'DK' => '+45', + 'VG' => '+1284', + 'DE' => '+49', + 'YE' => '+967', + 'DZ' => '+213', + 'US' => '+1', + 'UY' => '+598', + 'YT' => '+262', + 'UM' => '+1', + 'LB' => '+961', + 'LC' => '+1758', + 'LA' => '+856', + 'TV' => '+688', + 'TW' => '+886', + 'TT' => '+1868', + 'TR' => '+90', + 'LK' => '+94', + 'LI' => '+423', + 'LV' => '+371', + 'TO' => '+676', + 'LT' => '+370', + 'LU' => '+352', + 'LR' => '+231', + 'LS' => '+266', + 'TH' => '+66', + 'TF' => '', + 'TG' => '+228', + 'TD' => '+235', + 'TC' => '+1649', + 'LY' => '+218', + 'VA' => '+379', + 'VC' => '+1784', + 'AE' => '+971', + 'AD' => '+376', + 'AG' => '+1268', + 'AF' => '+93', + 'AI' => '+1264', + 'VI' => '+1340', + 'IS' => '+354', + 'IR' => '+98', + 'AM' => '+374', + 'AL' => '+355', + 'AO' => '+244', + 'AQ' => '', + 'AS' => '+1684', + 'AR' => '+54', + 'AU' => '+61', + 'AT' => '+43', + 'AW' => '+297', + 'IN' => '+91', + 'AX' => '+35818', + 'AZ' => '+994', + 'IE' => '+353', + 'ID' => '+62', + 'UA' => '+380', + 'QA' => '+974', + 'MZ' => '+258', + ]; + + + /** @var array flipped calling codes */ + protected static $flipped_calling_codes; + + + /** + * Convert a 2-character country code into its 3-character equivalent, or + * vice-versa, e.g. + * + * 1) given USA, returns US + * 2) given US, returns USA + * + * @since 5.4.3 + * + * @param string $code ISO-3166-alpha-2 or ISO-3166-alpha-3 country code + * @return string country code + */ + public static function convert_alpha_country_code( $code ) { + + $countries = 3 === strlen( $code ) ? array_flip( self::$alpha3 ) : self::$alpha3; + + return isset( $countries[ $code ] ) ? $countries[ $code ] : $code; + } + + + /** + * Converts an ISO 3166-alpha2 country code to an ISO 3166-alpha3 country code. + * + * @since 5.4.3 + * + * @param string $alpha2_code ISO 3166-alpha2 country code + * @return string ISO 3166-alpha3 country code + */ + public static function alpha2_to_alpha3( $alpha2_code ) { + + return isset( self::$alpha3[ $alpha2_code ] ) ? self::$alpha3[ $alpha2_code ] : ''; + } + + + /** + * Converts an ISO 3166-alpha2 country code to an ISO 3166-numeric country code. + * + * @since 5.4.3 + * + * @param string $alpha2_code ISO 3166-alpha2 country code + * @return string ISO 3166-numeric country code + */ + public static function alpha2_to_numeric( $alpha2_code ) { + + return isset( self::$numeric[ $alpha2_code ] ) ? self::$numeric[ $alpha2_code ] : ''; + } + + + /** + * Converts an ISO 3166-alpha2 country code to a calling code. + * + * This conversion is available in WC 3.6+ so we'll call out to that when available. + * + * @since 5.4.3 + * + * @param string $alpha2_code ISO 3166-alpha2 country code + * @return string calling code + */ + public static function alpha2_to_calling_code( $alpha2_code ) { + + // check not only for the right version, but if the helper is loaded & available + if ( SV_WC_Plugin_Compatibility::is_wc_version_gte( '3.6.0' ) && WC() && isset( WC()->countries ) && is_callable( [ WC()->countries, 'get_country_calling_code' ] ) ) { + + $calling_code = WC()->countries->get_country_calling_code( $alpha2_code ); + + } else { + + $calling_code = isset( self::$calling_codes[ $alpha2_code ] ) ? self::$calling_codes[ $alpha2_code ] : ''; + + // we can't really know _which_ code is to be used, so use the first + $calling_code = is_array( $calling_code ) ? $calling_code[0] : $calling_code; + } + + return $calling_code; + } + + + /** + * Converts an ISO 3166-alpha3 country code to an ISO 3166-alpha2 country code. + * + * @since 5.4.3 + * + * @param string $alpha3_code ISO 3166-alpha3 country code + * @return string ISO 3166-alpha2 country code + */ + public static function alpha3_to_alpha2( $alpha3_code ) { + + $countries = array_flip( self::$alpha3 ); + + return isset( $countries[ $alpha3_code ] ) ? $countries[ $alpha3_code ] : ''; + } + + + /** + * Converts an ISO 3166-alpha3 country code to an ISO 3166-numeric country code. + * + * @since 5.4.3 + * + * @param string $alpha3_code ISO 3166-alpha3 country code + * @return string ISO 3166-numeric country code + */ + public static function alpha3_to_numeric( $alpha3_code ) { + return self::alpha2_to_numeric( self::alpha3_to_alpha2( $alpha3_code ) ); + } + + + /** + * Converts an ISO 3166-alpha3 country code to a calling code. + * + * @since 5.4.3 + * + * @param string $alpha3_code ISO 3166-alpha3 country code + * @return string calling code + */ + public static function alpha3_to_calling_code( $alpha3_code ) { + return self::alpha2_to_calling_code( self::alpha3_to_alpha2( $alpha3_code ) ); + } + + + /** + * Converts an ISO 3166-numeric country code to an ISO 3166-alpha2 code. + * + * @since 5.4.3 + * + * @param string $numeric ISO 3166-numeric country code + * @return string ISO 3166-alpha2 country code + */ + public static function numeric_to_alpha2( $numeric ) { + + $codes = array_flip( self::$numeric ); + + return isset( $codes[ $numeric ] ) ? $codes[ $numeric ] : ''; + } + + + /** + * Converts an ISO 3166-numeric country code to an ISO 3166-alpha3 code. + * + * @since 5.4.3 + * + * @param string $numeric ISO 3166-numeric country code + * @return string ISO 3166-alpha3 country code + */ + public static function numeric_to_alpha3( $numeric ) { + return self::alpha2_to_alpha3( self::numeric_to_alpha2( $numeric ) ); + } + + + /** + * Converts an ISO 3166-numeric country code to a calling code. + * + * @since 5.4.3 + * + * @param string $numeric ISO 3166-numeric country code + * @return string calling code + */ + public static function numeric_to_calling_code( $numeric ) { + return self::alpha2_to_calling_code( self::numeric_to_alpha2( $numeric ) ); + } + + + /** + * Converts a country calling code to an ISO 3166-alpha2 code. + * + * @since 5.4.3 + * + * @param string $calling_code country calling code (includes leading '+') + * @return string ISO 3166-alpha2 code + */ + public static function calling_code_to_alpha2( $calling_code ) { + + $flipped_calling_codes = self::get_flipped_calling_codes(); + + return isset( $flipped_calling_codes[ $calling_code ] ) ? $flipped_calling_codes[ $calling_code ] : ''; + } + + + /** + * Converts a country calling code to an ISO 3166-alpha3 code. + * + * @since 5.4.3 + * + * @param string $calling_code country calling code (includes leading '+') + * @return string ISO 3166-alpha3 code + */ + public static function calling_code_to_alpha3( $calling_code ) { + + return self::alpha2_to_alpha3( self::calling_code_to_alpha2( $calling_code ) ); + } + + + /** + * Converts a country calling code to an ISO 3166-numeric code. + * + * @since 5.4.3 + * + * @param string $calling_code country calling code (includes leading '+') + * @return string ISO 3166-numeric code + */ + public static function calling_code_to_numeric( $calling_code ) { + + return self::alpha2_to_numeric( self::calling_code_to_alpha2( $calling_code ) ); + } + + + /** + * Gets the flipped version of the calling codes array. + * + * Since array_flip will fail on the calling codes array due to + * having some arrays as values, this custom function is necessary. + * + * @since 5.4.3 + * + * @return array + */ + public static function get_flipped_calling_codes() { + + if ( null === self::$flipped_calling_codes ) { + + $flipped_calling_codes = []; + + foreach ( self::$calling_codes as $alpha2 => $calling_code ) { + + if ( is_array( $calling_code ) ) { + + foreach ( $calling_code as $sub_code ) { + + $flipped_calling_codes[ $sub_code ] = $alpha2; + } + } else { + + $flipped_calling_codes[ $calling_code ] = $alpha2; + } + } + + self::$flipped_calling_codes = $flipped_calling_codes; + } + + return self::$flipped_calling_codes; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Handlers/Script_Handler.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Handlers/Script_Handler.php new file mode 100644 index 0000000..59f6d6b --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Handlers/Script_Handler.php @@ -0,0 +1,343 @@ +add_hooks(); + } + + + /** + * Adds the action and filter hooks. + * + * @since 5.7.0 + */ + protected function add_hooks() { + + add_action( 'wp_ajax_wc_' . $this->get_id() . '_log_script_event', [ $this, 'ajax_log_event' ] ); + add_action( 'wp_ajax_nopriv_wc_' . $this->get_id() . '_log_script_event', [ $this, 'ajax_log_event' ] ); + } + + + /** + * Returns the JS handler class name. + * + * @since 5.7.0 + * + * @return string + */ + protected function get_js_handler_class_name() { + + return sprintf( '%s_v5_11_4', $this->js_handler_base_class_name ); + } + + + /** + * Returns the JS handler object name. + * + * @since 5.7.0 + * + * @return string + */ + protected function get_js_handler_object_name() { + + return 'wc_' . $this->get_id() . '_handler'; + } + + + /** + * Gets the JS event triggered after the JS handler class is loaded. + * + * @since 5.7.0 + * + * @return string + */ + protected function get_js_loaded_event() { + + return sprintf( '%s_loaded', strtolower( $this->get_js_handler_class_name() ) ); + } + + + /** + * Gets the handler instantiation JS wrapped in a safe load technique. + * + * @since 5.7.0 + * + * @param array $additional_args additional handler arguments, if any + * @param string $handler_name handler name, if different from self::get_js_handler_class_name() + * @param string $object_name object name, if different from self::get_js_handler_object_name() + * @return string + */ + protected function get_safe_handler_js( array $additional_args = [], $handler_name = '', $object_name = '' ) { + + if ( ! $handler_name ) { + $handler_name = $this->get_js_handler_class_name(); + } + + $load_function = 'load_' . $this->get_id() . '_handler'; + + ob_start(); + + ?> + function () { + get_handler_js( $additional_args, $handler_name, $object_name ); ?> + } + + try { + + if ( 'undefined' !== typeof ) { + (); + } else { + window.jQuery( document.body ).on( 'get_js_loaded_event() ); ?>', ); + } + + } catch ( err ) { + + get_js_handler_event_debug_log_request(); ?> + } + get_js_handler_args() ); + + /** + * Filters the JavaScript handler arguments. + * + * @since 5.7.0 + * + * @param array $args arguments to pass to the JS handler + * @param Script_Handler $handler script handler instance + */ + $args = apply_filters( 'wc_' . $this->get_id() . '_js_args', $args, $this ); + + if ( ! $handler_name ) { + $handler_name = $this->get_js_handler_class_name(); + } + + if ( ! $object_name ) { + $object_name = $this->get_js_handler_object_name(); + } + + return sprintf( 'window.%1$s = new %2$s( %3$s );', esc_js( $object_name ), esc_js( $handler_name ), json_encode( $args ) ); + } + + + /** + * Gets the JS handler arguments. + * + * @since 5.7.0 + * + * @return array + */ + protected function get_js_handler_args() { + + return []; + } + + + /** + * Gets inline JavaScript code to issue an AJAX request to log a script error event. + * + * @since 5.7.0 + * + * @return string + */ + protected function get_js_handler_event_debug_log_request() { + + ob_start(); + + ?> + + var errorName = '', + errorMessage = ''; + + if ( 'undefined' === typeof err || 0 === err.length || ! err ) { + errorName = ''; + errorMessage = 'get_js_handler_class_name() ) ); ?>'; + } else { + errorName = 'undefined' !== typeof err.name ? err.name : ''; + errorMessage = 'undefined' !== typeof err.message ? err.message : ''; + } + + is_logging_enabled() ) : ?> + + console.log( [ errorName, errorMessage ].filter( Boolean ).join( ' ' ) ); + + + + jQuery.post( '', { + action: 'get_id() . '_log_script_event' ); ?>', + security: 'get_id_dasherized() . '-log-script-event' ) ); ?>', + name: errorName, + message: errorMessage, + } ); + + is_logging_enabled() ) { + return; + } + + try { + + if ( ! wp_verify_nonce( SV_WC_Helper::get_posted_value( 'security' ), 'wc-' . $this->get_id_dasherized() . '-log-script-event' ) ) { + throw new SV_WC_Plugin_Exception( 'Invalid nonce.' ); + } + + $name = isset( $_POST['name'] ) && is_string( $_POST['name'] ) ? trim( $_POST['name'] ) : ''; + $message = isset( $_POST['message'] ) && is_string( $_POST['message'] ) ? trim( $_POST['message'] ) : ''; + + if ( ! $message ) { + throw new SV_WC_Plugin_Exception( 'A message is required.' ); + } + + if ( $name ) { + $message = "{$name} {$message}"; + } + + $this->log_event( $message ); + + wp_send_json_success(); + + } catch ( SV_WC_Plugin_Exception $exception ) { + + wp_send_json_error( $exception->getMessage() ); + } + } + + + /** + * Adds a log entry. + * + * @since 5.7.0 + * + * @param string $message message to log + */ + abstract protected function log_event( $message ); + + + /** Conditional methods *******************************************************************************************/ + + + /** + * Determines whether logging is enabled. + * + * @since 5.7.0 + * + * @return bool + */ + protected function is_logging_enabled() { + + return false; + } + + + /** Getter methods ************************************************************************************************/ + + + /** + * Gets the ID of this script handler. + * + * @since 5.7.0 + * + * @return string + */ + abstract public function get_id(); + + + /** + * Gets the ID, but dasherized. + * + * @since 5.7.0 + * + * @return string + */ + public function get_id_dasherized() { + + return str_replace( '_', '-', $this->get_id() ); + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php new file mode 100644 index 0000000..e8f8e95 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php @@ -0,0 +1,668 @@ +plugin = $plugin; + + $this->add_hooks(); + } + + + /** + * Adds the action & filter hooks. + * + * @since 5.1.0 + */ + protected function add_hooks() { + + // handle activation + add_action( 'admin_init', array( $this, 'handle_activation' ) ); + + // handle deactivation + add_action( 'deactivate_' . $this->get_plugin()->get_plugin_file(), array( $this, 'handle_deactivation' ) ); + + if ( is_admin() && ! wp_doing_ajax() ) { + + // initialize the plugin lifecycle + add_action( 'wp_loaded', array( $this, 'init' ) ); + + // add the admin notices + add_action( 'init', array( $this, 'add_admin_notices' ) ); + } + + // catch any milestones triggered by action + add_action( 'wc_' . $this->get_plugin()->get_id() . '_milestone_reached', array( $this, 'trigger_milestone' ), 10, 3 ); + } + + + /** + * Initializes the plugin lifecycle. + * + * @since 5.2.0 + */ + public function init() { + + // potentially handle a new activation + $this->handle_activation(); + + $installed_version = $this->get_installed_version(); + $plugin_version = $this->get_plugin()->get_version(); + + // installed version lower than plugin version? + if ( version_compare( $installed_version, $plugin_version, '<' ) ) { + + if ( ! $installed_version ) { + + $this->install(); + + // store the upgrade event regardless if there was a routine for it + $this->store_event( 'install' ); + + /** + * Fires after the plugin has been installed. + * + * @since 5.1.0 + */ + do_action( 'wc_' . $this->get_plugin()->get_id() . '_installed' ); + + } else { + + $this->upgrade( $installed_version ); + + // store the upgrade event regardless if there was a routine for it + $this->add_upgrade_event( $installed_version ); + + // if the plugin never had any previous milestones, consider them all reached so their notices aren't displayed + if ( ! $this->get_milestone_version() ) { + $this->set_milestone_version( $plugin_version ); + } + + /** + * Fires after the plugin has been updated. + * + * @since 5.1.0 + * + * @param string $installed_version previously installed version + */ + do_action( 'wc_' . $this->get_plugin()->get_id() . '_updated', $installed_version ); + } + + // new version number + $this->set_installed_version( $plugin_version ); + } + } + + + /** + * Triggers plugin activation. + * + * We don't use register_activation_hook() as that can't be called inside + * the 'plugins_loaded' action. Instead, we rely on setting to track the + * plugin's activation status. + * + * @internal + * + * @link https://developer.wordpress.org/reference/functions/register_activation_hook/#comment-2100 + * + * @since 5.2.0 + */ + public function handle_activation() { + + if ( ! get_option( 'wc_' . $this->get_plugin()->get_id() . '_is_active', false ) ) { + + $this->activate(); + + /** + * Fires when the plugin is activated. + * + * @since 5.2.0 + */ + do_action( 'wc_' . $this->get_plugin()->get_id() . '_activated' ); + + update_option( 'wc_' . $this->get_plugin()->get_id() . '_is_active', 'yes' ); + } + } + + + /** + * Triggers plugin deactivation. + * + * @internal + * + * @since 5.2.0 + */ + public function handle_deactivation() { + + // if the enhanced admin is available, delete all of this plugin's notes on deactivation + if ( SV_WC_Plugin_Compatibility::is_enhanced_admin_available() ) { + + Notes_Helper::delete_notes_with_source( $this->get_plugin()->get_id_dasherized() ); + + // if this is a gateway plugin, also delete the plugin's individual gateway notes + if ( $this->get_plugin() instanceof SV_WC_Payment_Gateway_Plugin ) { + + foreach ( $this->get_plugin()->get_gateways() as $gateway ) { + Notes_Helper::delete_notes_with_source( $gateway->get_id_dasherized() ); + } + } + } + + $this->deactivate(); + + /** + * Fires when the plugin is deactivated. + * + * @since 5.2.0 + */ + do_action( 'wc_' . $this->get_plugin()->get_id() . '_deactivated' ); + + delete_option( 'wc_' . $this->get_plugin()->get_id() . '_is_active' ); + } + + + /** + * Handles plugin activation. + * + * Plugins can override this to run their own activation tasks. + * + * Important Note: operations here should never be destructive for existing + * data. Since we rely on an option to track activation, it's possible for + * this to run outside of genuine activations. + * + * @since 5.2.0 + */ + public function activate() { + + // stub + } + + + /** + * Handles plugin deactivation. + * + * Plugins can override this to run their own deactivation tasks. + * + * @since 5.2.0 + */ + public function deactivate() { + + // stub + } + + + /** + * Helper method to install default settings for a plugin. + * + * @since 5.2.0 + * + * @param array $settings settings in format required by WC_Admin_Settings + */ + public function install_default_settings( array $settings ) { + + foreach ( $settings as $setting ) { + + if ( isset( $setting['id'], $setting['default'] ) ) { + update_option( $setting['id'], $setting['default'] ); + } + } + } + + + /** + * Performs any install tasks. + * + * @since 5.2.0 + */ + protected function install() { + + // stub + } + + + /** + * Performs any upgrade tasks based on the provided installed version. + * + * @since 5.2.0 + * + * @param string $installed_version installed version + */ + protected function upgrade( $installed_version ) { + + foreach ( $this->upgrade_versions as $upgrade_version ) { + + $upgrade_method = 'upgrade_to_' . str_replace( array( '.', '-' ), '_', $upgrade_version ); + + if ( version_compare( $installed_version, $upgrade_version, '<' ) && is_callable( array( $this, $upgrade_method ) ) ) { + + $this->get_plugin()->log( "Starting upgrade to v{$upgrade_version}" ); + + $this->$upgrade_method( $installed_version ); + + $this->get_plugin()->log( "Upgrade to v{$upgrade_version} complete" ); + } + } + } + + + /** + * Adds any lifecycle admin notices. + * + * @since 5.1.0 + */ + public function add_admin_notices() { + + // display any milestone notices + foreach ( $this->get_milestone_messages() as $id => $message ) { + + // bail if this notice was already dismissed + if ( ! $this->get_plugin()->get_admin_notice_handler()->should_display_notice( $id ) ) { + continue; + } + + /** + * Filters a milestone notice message. + * + * @since 5.1.0 + * + * @param string $message message text to be used for the milestone notice + * @param string $id milestone ID + */ + $message = apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_milestone_message', $this->generate_milestone_notice_message( $message ), $id ); + + if ( $message ) { + + $this->get_plugin()->get_admin_notice_handler()->add_admin_notice( $message, $id, array( + 'always_show_on_settings' => false, + ) ); + + // only display one notice at a time + break; + } + } + } + + + /** Milestone Methods *****************************************************/ + + + /** + * Triggers a milestone. + * + * This will only be triggered if the install's "milestone version" is lower + * than $since. Plugins can specify $since as the version at which a + * milestone's feature was added. This prevents existing installs from + * triggering notices for milestones that have long passed, like a payment + * gateway's first successful payment. Omitting $since will assume the + * milestone has always existed and should only trigger for fresh installs. + * + * @since 5.1.0 + * + * @param string $id milestone ID + * @param string $message message to display to the user + * @param string $since the version since this milestone has existed in the plugin + * @return bool + */ + public function trigger_milestone( $id, $message, $since = '1.0.0' ) { + + // if the plugin was had milestones before this milestone was added, don't trigger it + if ( version_compare( $this->get_milestone_version(), $since, '>' ) ) { + return false; + } + + return $this->register_milestone_message( $id, $message ); + } + + + /** + * Generates a milestone notice message. + * + * @since 5.1.0 + * + * @param string $custom_message custom text that notes what milestone was completed. + * @return string + */ + protected function generate_milestone_notice_message( $custom_message ) { + + $message = ''; + + if ( $this->get_plugin()->get_reviews_url() ) { + + // to be prepended at random to each milestone notice + $exclamations = array( + __( 'Awesome', 'woocommerce-plugin-framework' ), + __( 'Fantastic', 'woocommerce-plugin-framework' ), + __( 'Cowabunga', 'woocommerce-plugin-framework' ), + __( 'Congratulations', 'woocommerce-plugin-framework' ), + __( 'Hot dog', 'woocommerce-plugin-framework' ), + ); + + $message = $exclamations[ array_rand( $exclamations ) ] . ', ' . esc_html( $custom_message ) . ' '; + + $message .= sprintf( + /* translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - tag, %4$s - tag, %5$s - tag */ + __( 'Are you having a great experience with %1$s so far? Please consider %2$sleaving a review%3$s! If things aren\'t going quite as expected, we\'re happy to help -- please %4$sreach out to our support team%5$s.', 'woocommerce-plugin-framework' ), + '' . esc_html( $this->get_plugin()->get_plugin_name() ) . '', + '', '', + '', '' + ); + } + + return $message; + } + + + /** + * Registers a milestone message to be displayed in the admin. + * + * @since 5.1.0 + * @see Lifecycle::generate_milestone_notice_message() + * + * @param string $id milestone ID + * @param string $message message to display to the user + * @return bool whether the message was successfully registered + */ + public function register_milestone_message( $id, $message ) { + + $milestone_messages = $this->get_milestone_messages(); + $dismissed_notices = array_keys( $this->get_plugin()->get_admin_notice_handler()->get_dismissed_notices() ); + + // get the total number of dismissed milestone messages + $dismissed_milestone_messages = array_intersect( array_keys( $milestone_messages ), $dismissed_notices ); + + // if the user has dismissed more than three milestone messages already, don't add any more + if ( count( $dismissed_milestone_messages ) > 3 ) { + return false; + } + + $milestone_messages[ $id ] = $message; + + return update_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_messages', $milestone_messages ); + } + + + /** Event history methods *****************************************************************************************/ + + + /** + * Adds an upgrade lifecycle event. + * + * @since 5.4.0 + * + * @param string $from_version version upgrading from + * @param array $data extra data to add + * @return false|int + */ + public function add_upgrade_event( $from_version, array $data = array() ) { + + $data = array_merge( array( + 'from_version' => $from_version, + ), $data ); + + return $this->store_event( 'upgrade', $data ); + } + + + /** + * Adds a migration lifecycle event. + * + * @since 5.4.0 + * + * @param string $from_plugin plugin migrating from + * @param string $from_version version migrating from + * @param array $data extra data to add + * @return false|int + */ + public function add_migrate_event( $from_plugin, $from_version = '', array $data = array() ) { + + $data = array_merge( array( + 'from_plugin' => $from_plugin, + 'from_version' => $from_version, + ), $data ); + + return $this->store_event( 'migrate', $data ); + } + + + /** + * Stores a lifecycle event. + * + * This can be used to log installs, upgrades, etc... + * + * Uses a direct database query to avoid cache issues. + * + * @since 5.4.0 + * + * @param string $name lifecycle event name + * @param array $data any extra data to store + * @return false|int + */ + public function store_event( $name, array $data = array() ) { + global $wpdb; + + $history = $this->get_event_history(); + + $event = array( + 'name' => wc_clean( $name ), + 'time' => (int) current_time( 'timestamp' ), + 'version' => wc_clean( $this->get_plugin()->get_version() ), + ); + + if ( ! empty( $data ) ) { + $event['data'] = wc_clean( $data ); + } + + array_unshift( $history, $event ); + + // limit to the last 30 events + $history = array_slice( $history, 0, 29 ); + + return $wpdb->replace( + $wpdb->options, + array( + 'option_name' => $this->get_event_history_option_name(), + 'option_value' => json_encode( $history ), + 'autoload' => 'no', + ), + array( + '%s', + '%s', + ) + ); + } + + + /** + * Gets the lifecycle event history. + * + * The last 30 events are stored, with the latest first. + * + * @since 5.4.0 + * + * @return array + */ + public function get_event_history() { + global $wpdb; + + $history = array(); + + $results = $wpdb->get_var( $wpdb->prepare( " + SELECT option_value + FROM {$wpdb->options} + WHERE option_name = %s + ", $this->get_event_history_option_name() ) ); + + if ( $results ) { + $history = json_decode( $results, true ); + } + + return is_array( $history ) ? $history : array(); + } + + + /** + * Gets the event history option name. + * + * @since 5.4.0 + * + * @return string + */ + protected function get_event_history_option_name() { + + return 'wc_' . $this->get_plugin()->get_id() . '_lifecycle_events'; + } + + + /** Utility Methods *******************************************************/ + + + /** + * Gets the registered milestone messages. + * + * @since 5.1.0 + * + * @return array + */ + protected function get_milestone_messages() { + + return get_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_messages', array() ); + } + + + /** + * Sets the milestone version. + * + * @since 5.1.0 + * + * @param string $version plugin version + * @return bool + */ + public function set_milestone_version( $version ) { + + $this->milestone_version = $version; + + return update_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_version', $version ); + } + + + /** + * Gets the milestone version. + * + * @since 5.1.0 + * + * @return string + */ + public function get_milestone_version() { + + if ( ! $this->milestone_version ) { + $this->milestone_version = get_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_version', '' ); + } + + return $this->milestone_version; + } + + + /** + * Gets the currently installed plugin version. + * + * @since 5.2.0 + * + * @return string + */ + protected function get_installed_version() { + + return get_option( $this->get_plugin()->get_plugin_version_name() ); + } + + + /** + * Sets the installed plugin version. + * + * @since 5.2.0 + * + * @param string $version version to set + */ + protected function set_installed_version( $version ) { + + update_option( $this->get_plugin()->get_plugin_version_name(), $version ); + } + + + /** + * Gets the plugin instance. + * + * @since 5.1.0 + * + * @return SV_WC_Plugin|SV_WC_Payment_Gateway_Plugin + */ + protected function get_plugin() { + + return $this->plugin; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Abstract_Settings.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Abstract_Settings.php new file mode 100644 index 0000000..72892e5 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Abstract_Settings.php @@ -0,0 +1,537 @@ +id = $id; + + $this->register_settings(); + $this->load_settings(); + } + + + /** + * Registers the settings. + * + * Plugins or payment gateways should overwrite this method to register their settings. + * + * @since 5.7.0 + */ + abstract protected function register_settings(); + + + /** + * Loads the values for all registered settings. + * + * @since 5.7.0 + */ + protected function load_settings() { + + foreach ( $this->settings as $setting_id => $setting ) { + + $value = get_option( $this->get_option_name_prefix() . '_' . $setting_id, null ); + $value = $this->get_value_from_database( $value, $setting ); + + $this->settings[ $setting_id ]->set_value( $value ); + } + } + + + /** + * Registers a setting. + * + * @param string $id unique setting ID + * @param string $type setting type + * @param array $args setting arguments + * @return bool + */ + public function register_setting( $id, $type, array $args = [] ) { + + try { + + if ( ! empty( $this->settings[ $id ] ) ) { + throw new Framework\SV_WC_Plugin_Exception( "Setting {$id} is already registered" ); + } + + if ( ! in_array( $type, $this->get_setting_types(), true ) ) { + throw new Framework\SV_WC_Plugin_Exception( "{$type} is not a valid setting type" ); + } + + $setting = new Setting(); + + $setting->set_id( $id ); + $setting->set_type( $type ); + + $args = wp_parse_args( $args, [ + 'name' => '', + 'description' => '', + 'is_multi' => false, + 'options' => [], + 'default' => null, + ] ); + + $setting->set_name( $args['name'] ); + $setting->set_description( $args['description'] ); + $setting->set_default( $args['default'] ); + $setting->set_is_multi( $args['is_multi'] ); + + if ( is_array( $args['options'] ) ) { + $setting->set_options( $args['options'] ); + } + + $this->settings[ $id ] = $setting; + + return true; + + } catch ( \Exception $exception ) { + + wc_doing_it_wrong( __METHOD__, 'Could not register setting: ' . $exception->getMessage(), '5.7.0' ); + + return false; + } + } + + + /** + * Unregisters a setting. + * + * @since 5.7.0 + * + * @param string $id setting ID to unregister + */ + public function unregister_setting( $id ) { + + unset( $this->settings[ $id ] ); + } + + + /** + * Registers a control for a setting. + * + * @since 5.7.0 + * + * @param string $setting_id the setting ID + * @param string $type the control type + * @param array $args optional args for the control + * @return bool + */ + public function register_control( $setting_id, $type, array $args = [] ) { + + try { + + if ( ! in_array( $type, $this->get_control_types(), true ) ) { + throw new \UnexpectedValueException( "{$type} is not a valid control type" ); + } + + $setting = $this->get_setting( $setting_id ); + + if ( ! $setting ) { + throw new \InvalidArgumentException( "Setting {$setting_id} does not exist" ); + } + + $setting_control_types = $this->get_setting_control_types( $setting ); + if ( ! empty( $setting_control_types ) && ! in_array( $type, $setting_control_types, true ) ) { + throw new \UnexpectedValueException( "{$type} is not a valid control type for setting {$setting->get_id()} of type {$setting->get_type()}" ); + } + + $args = wp_parse_args( $args, [ + 'name' => $setting->get_name(), + 'description' => $setting->get_description(), + 'options' => [], + ] ); + + $control = new Control(); + + $control->set_setting_id( $setting_id ); + $control->set_type( $type ); + $control->set_name( $args['name'] ); + $control->set_description( $args['description'] ); + + if ( is_array( $args['options'] ) ) { + $control->set_options( $args['options'], $setting->get_options() ); + } + + $setting->set_control( $control ); + + return true; + + } catch ( \Exception $exception ) { + + wc_doing_it_wrong( __METHOD__, 'Could not register setting control: ' . $exception->getMessage(), '5.7.0' ); + + return false; + } + } + + + /** + * Gets the settings ID. + * + * @since 5.7.0 + * + * @return string + */ + public function get_id() { + + return $this->id; + } + + + /** + * Gets registered settings. + * + * It returns all settings by default, but you can pass an array of IDs to filter the results. + * + * @param string[] $ids setting IDs to get + * @return Setting[] + */ + public function get_settings( array $ids = [] ) { + + $settings = $this->settings; + + if ( ! empty( $ids ) ) { + + foreach ( array_keys( $this->settings ) as $id ) { + + if ( ! in_array( $id, $ids, true ) ) { + unset( $settings[ $id ] ); + } + } + } + + return $settings; + } + + + /** + * Gets a setting object. + * + * @since 5.7.0 + * + * @param string $id setting ID to get + * @return Setting|null + */ + public function get_setting( $id ) { + + return ! empty( $this->settings[ $id ] ) ? $this->settings[ $id ] : null; + } + + + /** + * Gets the stored value for a setting. + * + * Optionally, will return the setting's default value if nothing is stored. + * + * @since 5.7.0 + * + * @param string $setting_id setting ID + * @param bool $with_default whether to return the default value if nothing is stored + * @return array|bool|float|int|string + * @throws Framework\SV_WC_Plugin_Exception + */ + public function get_value( $setting_id, $with_default = true ) { + + $setting = $this->get_setting( $setting_id ); + + if ( ! $setting ) { + throw new Framework\SV_WC_Plugin_Exception( "Setting {$setting_id} does not exist" ); + } + + $value = $setting->get_value(); + + if ( $with_default && null === $value ) { + $value = $setting->get_default(); + } + + return $value; + } + + + /** + * Updates the stored value for a setting. + * + * @since 5.7.0 + * + * @param string $setting_id setting ID + * @param array|bool|float|int|string $value + * @throws Framework\SV_WC_Plugin_Exception + */ + public function update_value( $setting_id, $value ) { + + $setting = $this->get_setting( $setting_id ); + + if ( ! $setting ) { + throw new Framework\SV_WC_Plugin_Exception( "Setting {$setting_id} does not exist", 404 ); + } + + // performs the validations and updates the value + $setting->update_value( $value ); + + $this->save( $setting_id ); + } + + + /** + * Deletes the stored value for a setting. + * + * @since 5.7.0 + * + * @param string $setting_id setting ID + * @return bool + * @throws Framework\SV_WC_Plugin_Exception + */ + public function delete_value( $setting_id ) { + + $setting = $this->get_setting( $setting_id ); + + if ( ! $setting ) { + throw new Framework\SV_WC_Plugin_Exception( "Setting {$setting_id} does not exist" ); + } + + $setting->set_value( null ); + + return delete_option( "{$this->get_option_name_prefix()}_{$setting->get_id()}" ); + } + + + /** + * Saves registered settings in their current state. + * + * It saves all settings by default, but you can pass a setting ID to save a specific setting. + * + * @since 5.7.0 + * + * @param string $setting_id setting ID + */ + public function save( $setting_id = '' ) { + + if ( ! empty( $setting_id ) ) { + $settings = [ $this->get_setting( $setting_id ) ]; + } else { + $settings = $this->settings; + } + + $settings = array_filter( $settings ); + + foreach ( $settings as $setting ) { + + $option_name = "{$this->get_option_name_prefix()}_{$setting->get_id()}"; + $setting_value = $setting->get_value(); + + if ( null === $setting_value ) { + + delete_option( $option_name ); + + } else { + + update_option( $option_name, $this->get_value_for_database( $setting ) ); + } + } + } + + + /** + * Converts the value of a setting to be stored in an option. + * + * @since 5.7.0 + * + * @param Setting $setting + * @return mixed + */ + protected function get_value_for_database( Setting $setting ) { + + $value = $setting->get_value(); + + if ( null !== $value && Setting::TYPE_BOOLEAN === $setting->get_type() ) { + $value = wc_bool_to_string( $value ); + } + + return $value; + } + + + /** + * Converts the stored value of a setting to the proper setting type. + * + * @since 5.7.0 + * + * @param mixed $value the value stored in an option + * @param Setting $setting + * @return mixed + */ + protected function get_value_from_database( $value, Setting $setting ) { + + if ( null !== $value ) { + + switch ( $setting->get_type() ) { + + case Setting::TYPE_BOOLEAN: + $value = wc_string_to_bool( $value ); + break; + + case Setting::TYPE_INTEGER: + $value = is_numeric( $value ) ? (int) $value : null; + break; + + case Setting::TYPE_FLOAT: + $value = is_numeric( $value ) ? (float) $value : null; + break; + } + } + + return $value; + } + + + /** + * Gets the list of valid setting types. + * + * @since 5.7.0 + * + * @return string[] + */ + public function get_setting_types() { + + $setting_types = [ + Setting::TYPE_STRING, + Setting::TYPE_URL, + Setting::TYPE_EMAIL, + Setting::TYPE_INTEGER, + Setting::TYPE_FLOAT, + Setting::TYPE_BOOLEAN, + ]; + + /** + * Filters the list of valid setting types. + * + * @param string[] $setting_types valid setting types + * @param Abstract_Settings $settings the settings handler instance + */ + return apply_filters( "wc_{$this->get_id()}_settings_api_setting_types", $setting_types, $this ); + } + + + /** + * Gets the list of valid control types. + * + * @since 5.7.0 + * + * @return string[] + */ + public function get_control_types() { + + $control_types = [ + Control::TYPE_TEXT, + Control::TYPE_TEXTAREA, + Control::TYPE_NUMBER, + Control::TYPE_EMAIL, + Control::TYPE_PASSWORD, + Control::TYPE_DATE, + Control::TYPE_CHECKBOX, + Control::TYPE_RADIO, + Control::TYPE_SELECT, + Control::TYPE_FILE, + Control::TYPE_COLOR, + Control::TYPE_RANGE, + ]; + + /** + * Filters the list of valid control types. + * + * @param string[] $control_types valid control types + * @param Abstract_Settings $settings the settings handler instance + */ + return apply_filters( "wc_{$this->get_id()}_settings_api_control_types", $control_types, $this ); + } + + + /** + * Returns the valid control types for a setting. + * + * @since 5.7.0 + * + * @param Setting $setting setting object + * @return string[] + */ + public function get_setting_control_types( $setting ) { + + /** + * Filters the list of valid control types for a setting. + * + * @param string[] $control_types valid control types + * @param string $setting_type setting type + * @param Setting $setting setting object + * @param Abstract_Settings $settings the settings handler instance + */ + return apply_filters( "wc_{$this->get_id()}_settings_api_setting_control_types", [], $setting->get_type(), $setting, $this ); + } + + + /** + * Gets the prefix for db option names. + * + * @since 5.7.0 + * + * @return string + */ + public function get_option_name_prefix() { + + return "wc_{$this->id}"; + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Control.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Control.php new file mode 100644 index 0000000..ce5f914 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Control.php @@ -0,0 +1,271 @@ + $label */ + protected $options = []; + + + /** Getter methods ************************************************************************************************/ + + + /** + * The setting ID to which this control belongs. + * + * @since 5.7.0 + * + * @return null|string + */ + public function get_setting_id() { + + return $this->setting_id; + } + + + /** + * Gets the control type. + * + * @since 5.7.0 + * + * @return null|string + */ + public function get_type() { + + return $this->type; + } + + + /** + * Gets the control name. + * + * @since 5.7.0 + * + * @return string + */ + public function get_name() { + + return $this->name; + } + + + /** + * Gets the control description. + * + * @since 5.7.0 + * + * @return string + */ + public function get_description() { + + return $this->description; + } + + + /** + * Gets the control options. + * + * As $option => $label for display. + * + * @since 5.7.0 + * + * @return array + */ + public function get_options() { + + return $this->options; + } + + + /** Setter methods ************************************************************************************************/ + + + /** + * Sets the setting ID. + * + * @since 5.7.0 + * + * @param string $value setting ID to set + * @throws Framework\SV_WC_Plugin_Exception + */ + public function set_setting_id( $value ) { + + if ( ! is_string( $value ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Setting ID value must be a string' ); + } + + $this->setting_id = $value; + } + + + /** + * Sets the type. + * + * @since 5.7.0 + * + * @param string $value setting ID to set + * @param string[] $valid_types allowed control types + * @throws Framework\SV_WC_Plugin_Exception + */ + public function set_type( $value, array $valid_types = [] ) { + + if ( ! empty( $valid_types ) && ! in_array( $value, $valid_types, true ) ) { + + throw new Framework\SV_WC_Plugin_Exception( sprintf( + 'Control type must be one of %s', + Framework\SV_WC_Helper::list_array_items( $valid_types, 'or' ) + ) ); + } + + $this->type = $value; + } + + + /** + * Sets the name. + * + * @since 5.7.0 + * + * @param string $value control name to set + * @throws Framework\SV_WC_Plugin_Exception + */ + public function set_name( $value ) { + + if ( ! is_string( $value ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Control name value must be a string' ); + } + + $this->name = $value; + } + + + /** + * Sets the description. + * + * @since 5.7.0 + * + * @param string $value control description to set + * @throws Framework\SV_WC_Plugin_Exception + */ + public function set_description( $value ) { + + if ( ! is_string( $value ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Control description value must be a string' ); + } + + $this->description = $value; + } + + + /** + * Sets the options. + * + * @since 5.7.0 + * + * @param array $options options to set + * @param array $valid_options valid option keys to check against + */ + public function set_options( array $options, array $valid_options = [] ) { + + if ( ! empty( $valid_options ) ) { + + foreach ( array_keys( $options ) as $key ) { + + if ( ! in_array( $key, $valid_options, true ) ) { + unset( $options[ $key ] ); + } + } + } + + $this->options = $options; + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Setting.php b/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Setting.php new file mode 100644 index 0000000..215cd68 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/Settings_API/Setting.php @@ -0,0 +1,479 @@ +id; + } + + + /** + * Gets the setting type. + * + * @since 5.7.0 + * + * @return string + */ + public function get_type() { + + return $this->type; + } + + + /** + * Gets the setting name. + * + * @since 5.7.0 + * + * @return string + */ + public function get_name() { + + return $this->name; + } + + + /** + * Gets the setting description. + * + * @since 5.7.0 + * + * @return string + */ + public function get_description() { + + return $this->description; + } + + + /** + * Returns whether the setting holds an array of multiple values. + * + * @since 5.7.0 + * + * @return bool + */ + public function is_is_multi() { + + return $this->is_multi; + } + + + /** + * Gets the setting options. + * + * @since 5.7.0 + * + * @return array + */ + public function get_options() { + + return $this->options; + } + + + /** + * Gets the setting default value. + * + * @since 5.7.0 + * + * @return array|bool|float|int|string|null + */ + public function get_default() { + + return $this->default; + } + + + /** + * Gets the setting current value. + * + * @since 5.7.0 + * + * @return array|bool|float|int|string + */ + public function get_value() { + + return $this->value; + } + + + /** + * Gets the setting control. + * + * @since 5.7.0 + * + * @return Control + */ + public function get_control() { + + return $this->control; + } + + + /** Setter Methods ************************************************************************************************/ + + + /** + * Sets the setting ID. + * + * @since 5.7.0 + * + * @param string $id + */ + public function set_id( $id ) { + + $this->id = $id; + } + + + /** + * Sets the setting type. + * + * @since 5.7.0 + * + * @param string $type + */ + public function set_type( $type ) { + + $this->type = $type; + } + + + /** + * Sets the setting name. + * + * @since 5.7.0 + * + * @param string $name + */ + public function set_name( $name ) { + + $this->name = $name; + } + + + /** + * Sets the setting description. + * + * @since 5.7.0 + * + * @param string $description + */ + public function set_description( $description ) { + + $this->description = $description; + } + + + /** + * Sets whether the setting holds an array of multiple values. + * + * @since 5.7.0 + * + * @param bool $is_multi + */ + public function set_is_multi( $is_multi ) { + + $this->is_multi = $is_multi; + } + + + /** + * Sets the setting options. + * + * @since 5.7.0 + * + * @param array $options + */ + public function set_options( $options ) { + + foreach ( $options as $key => $option ) { + + if ( ! $this->validate_value( $option ) ) { + unset( $options[ $key ] ); + } + } + + $this->options = $options; + } + + + /** + * Sets the setting default value. + * + * @since 5.7.0 + * + * @param array|bool|float|int|string|null $value default value to set + */ + public function set_default( $value ) { + + if ( $this->is_is_multi() ) { + + $_value = array_filter( (array) $value, [ $this, 'validate_value' ] ); + + // clear the default if all values were invalid + $value = ! empty( $_value ) ? $_value : null; + + } elseif ( ! $this->validate_value( $value ) ) { + + $value = null; + } + + $this->default = $value; + } + + + /** + * Sets the setting current value. + * + * @since 5.7.0 + * + * @param array|bool|float|int|string $value + */ + public function set_value( $value ) { + + $this->value = $value; + } + + + /** + * Sets the setting control. + * + * @since 5.7.0 + * + * @param Control $control + */ + public function set_control( $control ) { + + $this->control = $control; + } + + + /** + * Sets the setting current value, after validating it against the type and, if set, options. + * + * @since 5.7.0 + * + * @param array|bool|float|int|string $value + * @throws Framework\SV_WC_Plugin_Exception + */ + public function update_value( $value ) { + + if ( ! $this->validate_value( $value ) ) { + + throw new Framework\SV_WC_Plugin_Exception( "Setting value for setting {$this->id} is not valid for the setting type {$this->type}", 400 ); + + } elseif ( ! empty( $this->options ) && ! in_array( $value, $this->options ) ) { + + throw new Framework\SV_WC_Plugin_Exception( sprintf( + 'Setting value for setting %s must be one of %s', + $this->id, + Framework\SV_WC_Helper::list_array_items( $this->options, 'or' ) + ), 400 ); + + } else { + + $this->set_value( $value ); + } + } + + + /** + * Validates the setting value. + * + * @since 5.7.0 + * + * @param array|bool|float|int|string $value + * @return bool + */ + public function validate_value( $value ) { + + $validate_method = "validate_{$this->get_type()}_value"; + + return is_callable( [ $this, $validate_method ] ) ? $this->$validate_method( $value ) : true; + } + + + /** + * Validates a string value. + * + * @since 5.7.0 + * + * @param array|bool|float|int|string $value value to validate + * @return bool + */ + protected function validate_string_value( $value ) { + + return is_string( $value ); + } + + + /** + * Validates a URL value. + * + * @since 5.7.0 + * + * @param array|bool|float|int|string $value value to validate + * @return bool + */ + protected function validate_url_value( $value ) { + + return wc_is_valid_url( $value ); + } + + + /** + * Validates an email value. + * + * @since 5.7.0 + * + * @param mixed $value value to validate + * @return bool + */ + protected function validate_email_value( $value ) { + + return (bool) is_email( $value ); + } + + + /** + * Validates an integer value. + * + * @since 5.7.0 + * + * @param mixed $value value to validate + * @return bool + */ + public function validate_integer_value( $value ) { + + return is_int( $value ); + } + + + /** + * Validates a float value. + * + * @since 5.7.0 + * + * @param mixed $value value to validate + * @return bool + */ + protected function validate_float_value( $value ) { + + return is_int( $value ) || is_float( $value ); + } + + + /** + * Validates a boolean value. + * + * @since 5.7.0 + * + * @param mixed $value value to validate + * @return bool + */ + protected function validate_boolean_value( $value ) { + + return is_bool( $value ); + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/admin/Notes_Helper.php b/vendor/skyverge/wc-plugin-framework/woocommerce/admin/Notes_Helper.php new file mode 100644 index 0000000..8c60d96 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/admin/Notes_Helper.php @@ -0,0 +1,150 @@ +get_notes_with_name( $name ); + + } catch ( \Exception $exception ) {} + + return $note_ids; + } + + + /** + * Gets all note IDs from the given source. + * + * @since 5.6.1 + * + * @param string $source note source + * @return int[] + */ + public static function get_note_ids_with_source( $source ) { + global $wpdb; + + return $wpdb->get_col( + $wpdb->prepare( + "SELECT note_id FROM {$wpdb->prefix}wc_admin_notes WHERE source = %s ORDER BY note_id ASC", + $source + ) + ); + } + + + /** + * Deletes all notes from the given source. + * + * @since 5.6.1 + * + * @param string $source source name + */ + public static function delete_notes_with_source( $source ) { + + foreach ( self::get_note_ids_with_source( $source ) as $note_id ) { + + if ( $note = WooCommerce_Admin_Notes\WC_Admin_Notes::get_note( $note_id ) ) { + $note->delete(); + } + } + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php b/vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php new file mode 100644 index 0000000..6cba158 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php @@ -0,0 +1,1299 @@ +required_capability ) ) { + return; + } + + $this->id = $plugin->get_id(); + $this->plugin = $plugin; + + // register the steps + $this->register_steps(); + + /** + * Filters the registered setup wizard steps. + * + * @since 5.2.2 + * + * @param array $steps registered steps + */ + $this->steps = apply_filters( "wc_{$this->id}_setup_wizard_steps", $this->steps, $this ); + + // only continue if there are registered steps + if ( $this->has_steps() ) { + + // if requesting the wizard + if ( $this->is_setup_page() ) { + + $this->init_setup(); + + // otherwise, add the hooks for customizing the regular admin + } else { + + $this->add_hooks(); + + // mark the wizard as complete if specifically requested + if ( Framework\SV_WC_Helper::get_requested_value( "wc_{$this->id}_setup_wizard_complete" ) ) { + $this->complete_setup(); + } + } + } + } + + + /** + * Registers the setup steps. + * + * Plugins should extend this to register their own steps. + * + * @since 5.2.2 + */ + abstract protected function register_steps(); + + + /** + * Adds the action & filter hooks. + * + * @since 5.2.2 + */ + protected function add_hooks() { + + // add any admin notices + add_action( 'admin_notices', array( $this, 'add_admin_notices' ) ); + + // add a 'Setup' link to the plugin action links if the wizard hasn't been completed + if ( ! $this->is_complete() ) { + add_filter( 'plugin_action_links_' . plugin_basename( $this->get_plugin()->get_plugin_file() ), array( $this, 'add_setup_link' ), 20 ); + } + } + + + /** + * Adds any admin notices. + * + * @since 5.2.2 + */ + public function add_admin_notices() { + + if ( Framework\SV_WC_Helper::is_current_screen( 'plugins' ) || $this->get_plugin()->is_plugin_settings() ) { + + if ( $this->is_complete() && $this->get_documentation_notice_message() ) { + $notice_id = "wc_{$this->id}_docs"; + $message = $this->get_documentation_notice_message(); + } else { + $notice_id = "wc_{$this->id}_setup"; + $message = $this->get_setup_notice_message(); + } + + $this->get_plugin()->get_admin_notice_handler()->add_admin_notice( $message, $notice_id, array( + 'always_show_on_settings' => false, + ) ); + } + } + + + /** + * Gets the new installation documentation notice message. + * + * This prompts users to read the docs and is displayed if the wizard has + * already been completed. + * + * @since 5.2.2 + * + * @return string + */ + protected function get_documentation_notice_message() { + + if ( $this->get_plugin()->get_documentation_url() ) { + + $message = sprintf( + /** translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - tag */ + __( 'Thanks for installing %1$s! To get started, take a minute to %2$sread the documentation%3$s :)', 'woocommerce-plugin-framework' ), + esc_html( $this->get_plugin()->get_plugin_name() ), + '', '' + ); + + } else { + + $message = ''; + } + + return $message; + } + + + /** + * Gets the new installation setup notice message. + * + * This prompts users to start the setup wizard and is displayed if the + * wizard has not yet been completed. + * + * @since 5.2.2 + * + * @return string + */ + protected function get_setup_notice_message() { + + return sprintf( + /** translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - tag */ + __( 'Thanks for installing %1$s! To get started, take a minute to complete these %2$squick and easy setup steps%3$s :)', 'woocommerce-plugin-framework' ), + esc_html( $this->get_plugin()->get_plugin_name() ), + '', '' + ); + } + + + /** + * Adds a 'Setup' link to the plugin action links if the wizard hasn't been completed. + * + * This will override the plugin's standard "Configure" link with a link to this setup wizard. + * + * @internal + * + * @since 5.2.2 + * + * @param array $action_links plugin action links + * @return array + */ + public function add_setup_link( $action_links ) { + + // remove the standard plugin "Configure" link + unset( $action_links['configure'] ); + + $setup_link = array( + 'setup' => sprintf( '%s', $this->get_setup_url(), esc_html__( 'Setup', 'woocommerce-plugin-framework' ) ), + ); + + return array_merge( $setup_link, $action_links ); + } + + + /** + * Initializes setup. + * + * @since 5.2.2 + */ + protected function init_setup() { + + // get a step ID from $_GET + $current_step = sanitize_key( Framework\SV_WC_Helper::get_requested_value( 'step' ) ); + $current_action = sanitize_key( Framework\SV_WC_Helper::get_requested_value( 'action' ) ); + + if ( ! $current_action ) { + + if ( $this->has_step( $current_step ) ) { + $this->current_step = $current_step; + } elseif ( $first_step_url = $this->get_step_url( key( $this->steps ) ) ) { + wp_safe_redirect( $first_step_url ); + exit; + } else { + wp_safe_redirect( $this->get_dashboard_url() ); + exit; + } + } + + // add the page to WP core + add_action( 'admin_menu', array( $this, 'add_page' ) ); + + // renders the entire setup page markup + add_action( 'admin_init', array( $this, 'render_page' ) ); + } + + + /** + * Adds the page to WordPress core. + * + * While this doesn't output any markup/menu items, it is essential to officially register the page to avoid permissions issues. + * + * @internal + * + * @since 5.2.2 + */ + public function add_page() { + + add_dashboard_page( '', '', $this->required_capability, $this->get_slug(), '' ); + } + + + /** + * Renders the entire setup page markup. + * + * @internal + * + * @since 5.2.2 + */ + public function render_page() { + + // maybe save and move onto the next step + $error_message = Framework\SV_WC_Helper::get_posted_value( 'save_step' ) ? $this->save_step( $this->current_step ) : ''; + + $page_title = sprintf( + /* translators: Placeholders: %s - plugin name */ + __( '%s › Setup', 'woocommerce-plugin-framework' ), + $this->get_plugin()->get_plugin_name() + ); + + // add the step name to the page title + if ( ! empty( $this->steps[ $this->current_step ]['name'] ) ) { + $page_title .= " › {$this->steps[ $this->current_step ]['name']}"; + } + + $this->load_scripts_styles(); + + ob_start(); + + ?> + + > + + + + <?php echo esc_html( $page_title ); ?> + + + + + + render_header(); ?> + render_steps(); ?> + render_content( $error_message ); ?> + render_footer(); ?> + + + id}_setup_wizard_save" ) ) { + throw new Framework\SV_WC_Plugin_Exception( $error_message ); + } + + if ( $this->has_step( $step_id ) ) { + + // if the step has a saving callback defined, save the form fields + if ( is_callable( $this->steps[ $step_id ]['save'] ) ) { + call_user_func( $this->steps[ $step_id ]['save'], $this ); + } + + // move to the next step + wp_safe_redirect( $this->get_next_step_url( $step_id ) ); + exit; + } + + } catch ( Framework\SV_WC_Plugin_Exception $exception ) { + + return $exception->getMessage() ? $exception->getMessage() : $error_message; + } + } + + + /** + * Registers and enqueues the wizard's scripts and styles. + * + * @since 5.2.2 + */ + protected function load_scripts_styles() { + + // block UI + wp_register_script( 'jquery-blockui', WC()->plugin_url() . '/assets/js/jquery-blockui/jquery.blockUI.min.js', array( 'jquery' ), '2.70', true ); + + // enhanced dropdowns + wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full.min.js', array( 'jquery' ), '1.0.0' ); + wp_register_script( 'wc-enhanced-select', WC()->plugin_url() . '/assets/js/admin/wc-enhanced-select.min.js', array( 'jquery', 'selectWoo' ), $this->get_plugin()->get_version() ); + wp_localize_script( + 'wc-enhanced-select', + 'wc_enhanced_select_params', + array( + 'i18n_no_matches' => _x( 'No matches found', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_ajax_error' => _x( 'Loading failed', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_input_too_short_1' => _x( 'Please enter 1 or more characters', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_input_too_short_n' => _x( 'Please enter %qty% or more characters', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_input_too_long_1' => _x( 'Please delete 1 character', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_input_too_long_n' => _x( 'Please delete %qty% characters', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_selection_too_long_1' => _x( 'You can only select 1 item', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_selection_too_long_n' => _x( 'You can only select %qty% items', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_load_more' => _x( 'Loading more results…', 'enhanced select', 'woocommerce-plugin-framework' ), + 'i18n_searching' => _x( 'Searching…', 'enhanced select', 'woocommerce-plugin-framework' ), + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'search_products_nonce' => wp_create_nonce( 'search-products' ), + 'search_customers_nonce' => wp_create_nonce( 'search-customers' ), + ) + ); + + // WooCommerce Setup core styles + wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), $this->get_plugin()->get_version() ); + wp_enqueue_style( 'wc-setup', WC()->plugin_url() . '/assets/css/wc-setup.css', array( 'dashicons', 'install' ), $this->get_plugin()->get_version() ); + + // framework bundled styles + wp_enqueue_style( 'sv-wc-admin-setup', $this->get_plugin()->get_framework_assets_url() . '/css/admin/sv-wc-plugin-admin-setup-wizard.min.css', array( 'wc-setup' ), $this->get_plugin()->get_version() ); + wp_enqueue_script( 'sv-wc-admin-setup', $this->get_plugin()->get_framework_assets_url() . '/js/admin/sv-wc-plugin-admin-setup-wizard.min.js', array( 'jquery', 'wc-enhanced-select', 'jquery-blockui' ), $this->get_plugin()->get_version() ); + } + + + /** Header Methods ************************************************************************************************/ + + + /** + * Renders the header markup. + * + * @since 5.2.2 + */ + protected function render_header() { + + $title = $this->get_plugin()->get_plugin_name(); + $link_url = $this->get_plugin()->get_sales_page_url(); + $image_url = $this->get_header_image_url(); + + $header_content = $image_url ? '' . esc_attr( $title ) . '' : $title; + + ?> +

    + + + + + +

    + +
      + + steps as $id => $step ) : ?> + + current_step ) : ?> +
    1. + is_step_complete( $id ) ) : ?> +
    2. + +
    3. + + + + +
    4. + +
    + +
    + + is_finished() ) : ?> + + render_finished(); ?> + + complete_setup(); ?> + + + + + is_started() ) : ?> + render_welcome(); ?> + + + + + render_error( $error_message ); ?> + + +
    + render_step( $this->current_step ); ?> + id}_setup_wizard_save", 'nonce' ); ?> +
    + + + +
    + %s

    ', esc_html( $message ) ); + } + } + + + /** + * Renders a default welcome note. + * + * @since 5.2.2 + */ + protected function render_welcome() { + + ?> +

    render_welcome_heading()?>

    +

    render_welcome_text(); ?>

    + get_plugin()->get_plugin_name() + ); + } + + + /** + * Renders the default welcome note text. + * + * @since 5.2.2 + */ + protected function render_welcome_text() { + + esc_html_e( 'This quick setup wizard will help you configure the basic settings and get you started.', 'woocommerce-plugin-framework' ); + } + + + /** + * Renders the finished screen markup. + * + * This is what gets displayed after all of the steps have been completed or skipped. + * + * @since 5.2.2 + */ + protected function render_finished() { + + ?> +

    get_plugin()->get_plugin_name() ) ); ?>

    + render_before_next_steps(); ?> + render_next_steps(); ?> + render_after_next_steps(); ?> + get_next_steps(); + $additional_actions = $this->get_additional_actions(); + + if ( ! empty( $next_steps ) || ! empty( $additional_actions ) ) : + + ?> +
      + + + +
    • +
      + +

      +

      + + +

      + + +
      + +
      +

      + + + + + +

      +
      +
    • + + + + + +
    • +
      +

      +
      +
      + +

      + + $url ) : ?> + + + + + + + +

      +
      +
    • + + + +
    + get_plugin()->get_documentation_url() ) { + + $steps['view-docs'] = array( + 'name' => __( 'View the Docs', 'woocommerce-plugin-framework' ), + 'label' => __( 'See more setup options', 'woocommerce-plugin-framework' ), + 'description' => __( 'Learn more about customizing the plugin', 'woocommerce-plugin-framework' ), + 'url' => $this->get_plugin()->get_documentation_url(), + ); + } + + return $steps; + } + + + /** + * Gets the additional steps. + * + * These are secondary actions. + * + * @since 5.2.2 + * + * @return array + */ + protected function get_additional_actions() { + + $next_steps = $this->get_next_steps(); + $actions = array(); + + if ( $this->get_plugin()->get_settings_url() ) { + $actions[ __( 'Review Your Settings', 'woocommerce-plugin-framework' ) ] = $this->get_plugin()->get_settings_url(); + } + + if ( empty( $next_steps['view-docs'] ) && $this->get_plugin()->get_documentation_url() ) { + $actions[ __( 'View the Docs', 'woocommerce-plugin-framework' ) ] = $this->get_plugin()->get_documentation_url(); + } + + if ( $this->get_plugin()->get_reviews_url() ) { + $actions[ __( 'Leave a Review', 'woocommerce-plugin-framework' ) ] = $this->get_plugin()->get_reviews_url(); + } + + return $actions; + } + + + /** + * Renders a given step's markup. + * + * This will display a title, whatever get's rendered by the step's view + * callback, then the navigation buttons. + * + * @since 5.2.2 + * + * @param string $step_id step ID to render + */ + protected function render_step( $step_id ) { + + call_user_func( $this->steps[ $step_id ]['view'], $this ); + + ?> +

    + + + + steps[ $step_id ]['save'] ) ) : ?> + + + + + + + + +

    + render_toggle_form_field( $key, $args, $value ); + } else { + woocommerce_form_field( $key, $args, $value ); + } + } + + + /** + * Renders the toggle form field. + * + * This requires special markup for the toggle UI. + * + * @since 5.2.2 + * + * @param string $key field key + * @param array $args field args - @see woocommerce_form_field() + * @param string|null $value field value + */ + public function render_toggle_form_field( $key, $args, $value ) { + + $args = wp_parse_args( $args, array( + 'type' => 'text', + 'label' => '', + 'description' => '', + 'required' => false, + 'id' => $key, + 'class' => array(), + 'label_class' => array(), + 'input_class' => array(), + 'custom_attributes' => array(), + 'default' => false, + 'allow_html' => false, + ) ); + + $args['class'][] = 'toggle'; + + if ( $args['required'] ) { + $args['class'][] = 'validate-required'; + } + + if ( null === $value ) { + $value = $args['default']; + } + + $custom_attributes = array(); + $args['custom_attributes'] = array_filter( (array) $args['custom_attributes'], 'strlen' ); + + if ( $args['description'] ) { + $args['custom_attributes']['aria-describedby'] = $args['id'] . '-description'; + } + + if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) { + foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) { + $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"'; + } + } + + $enabled = $value || $args['default']; + + if ( $enabled ) { + $args['class'][] = 'enabled'; + } + + ?> +
    + +

    + + +

    + +

    + + +
    + + + + /> + +
    + +
    + + is_finished() ) : ?> + + is_started() ) : ?> + + + + + has_step( $id ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Invalid step ID' ); + } + + // invalid name + if ( ! is_string( $name ) || empty( $name ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Invalid step name' ); + } + + // invalid view callback + if ( ! is_callable( $view_callback ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Invalid view callback' ); + } + + // invalid save callback + if ( null !== $save_callback && ! is_callable( $save_callback ) ) { + throw new Framework\SV_WC_Plugin_Exception( 'Invalid save callback' ); + } + + $this->steps[ $id ] = array( + 'name' => $name, + 'view' => $view_callback, + 'save' => $save_callback, + ); + + return true; + + } catch ( Framework\SV_WC_Plugin_Exception $exception ) { + + wc_doing_it_wrong( __METHOD__, $exception->getMessage(), '5.2.2' ); + + return false; + } + } + + + /** + * Marks the setup as complete. + * + * @since 5.2.2 + * + * @return bool + */ + public function complete_setup() { + + return update_option( "wc_{$this->id}_setup_wizard_complete", 'yes' ); + } + + + /** Conditional Methods *******************************************************************************************/ + + + /** + * Determines if the current page is the setup wizard page. + * + * @since 5.2.2 + * + * @return bool + */ + public function is_setup_page() { + + return is_admin() && $this->get_slug() === Framework\SV_WC_Helper::get_requested_value( 'page' ); + } + + + /** + * Determines if a step is the current one displayed. + * + * @since 5.2.2 + * + * @param string $step_id step ID + * @return bool + */ + public function is_current_step( $step_id ) { + + return $this->current_step === $step_id; + } + + + /** + * Determines if setup has started. + * + * @since 5.2.2 + * + * @return bool + */ + public function is_started() { + + $steps = array_keys( $this->steps ); + + return $this->current_step && $this->current_step === reset( $steps ); + } + + + /** + * Determines if setup has completed all of the steps. + * + * @since 5.2.2 + * + * @return bool + */ + public function is_finished() { + + return self::ACTION_FINISH === Framework\SV_WC_Helper::get_requested_value( 'action' ); + } + + + /** + * Determines if the setup wizard has been completed. + * + * This will be true if any user has been redirected back to the regular + * WordPress dashboard, either manually or after finishing the steps. + * + * @since 5.2.2 + * + * @return bool + */ + public function is_complete() { + + return 'yes' === get_option( "wc_{$this->id}_setup_wizard_complete", 'no' ); + } + + + /** + * Determines if the given step has been completed. + * + * @since 5.2.2 + * + * @param string $step_id step ID to check + * @return bool + */ + public function is_step_complete( $step_id ) { + + return array_search( $this->current_step, array_keys( $this->steps ), true ) > array_search( $step_id, array_keys( $this->steps ), true ) || $this->is_finished(); + } + + + /** + * Determines if the wizard has steps to display. + * + * @since 5.2.2 + * + * @return bool + */ + public function has_steps() { + + return is_array( $this->steps ) && ! empty( $this->steps ); + } + + + /** + * Determines if this setup handler has a given step. + * + * @since 5.2.2 + * + * @param string $step_id step ID to check + * @return bool + */ + public function has_step( $step_id ) { + + return ! empty( $this->steps[ $step_id ] ); + } + + + /** Getter Methods ************************************************************************************************/ + + + /** + * Gets a given step's title. + * + * @since 5.2.2 + * + * @param string $step_id step ID (optional: will assume the current step if unspecified) + * @return string + */ + public function get_step_title( $step_id = '' ) { + + $step_title = ''; + + if ( ! $step_id ) { + $step_id = $this->current_step; + } + + if ( isset( $this->steps[ $step_id ]['name'] ) ) { + $step_title = $this->steps[ $step_id ]['name']; + } + + return $step_title; + } + + + /** + * Gets the Setup Wizard URL. + * + * @since 5.2.2 + * + * @return string + */ + public function get_setup_url() { + + return add_query_arg( 'page', $this->get_slug(), admin_url( 'index.php' ) ); + } + + + /** + * Gets the URL for the next step based on a current step. + * + * @since 5.2.2 + * + * @param string $step_id step ID to base "next" off of - defaults to this class's internal pointer + * @return string + */ + public function get_next_step_url( $step_id = '' ) { + + if ( ! $step_id ) { + $step_id = $this->current_step; + } + + $steps = array_keys( $this->steps ); + + // if on the last step, next is the final finish step + if ( end( $steps ) === $step_id ) { + + $url = $this->get_finish_url(); + + } else { + + $step_index = array_search( $step_id, $steps, true ); + + // if the current step is found, use the next in the array. otherwise, the first + $step = false !== $step_index ? $steps[ $step_index + 1 ] : reset( $steps ); + + $url = add_query_arg( 'step', $step ); + } + + return $url; + } + + + /** + * Gets a given step's URL. + * + * @since 5.2.2 + * + * @param string $step_id step ID + * @return string|false + */ + public function get_step_url( $step_id ) { + + $url = false; + + if ( $this->has_step( $step_id ) ) { + $url = add_query_arg( 'step', $step_id, remove_query_arg( 'action' ) ); + } + + return $url; + } + + + /** + * Gets the "finish" action URL. + * + * @since 5.2.2 + * + * @return string + */ + protected function get_finish_url() { + + return add_query_arg( 'action', self::ACTION_FINISH, remove_query_arg( 'step' ) ); + } + + + /** + * Gets the return URL. + * + * Can be used to return the user to the dashboard. The plugin's settings URL + * will be used if it exists, otherwise the general dashboard URL. + * + * @since 5.2.2 + * + * @return string + */ + protected function get_dashboard_url() { + + $settings_url = $this->get_plugin()->get_settings_url(); + $dashboard_url = ! empty( $settings_url ) ? $settings_url : admin_url(); + + return add_query_arg( "wc_{$this->id}_setup_wizard_complete", true, $dashboard_url ); + } + + + /** + * Gets the setup setup handler's slug. + * + * @since 5.2.2 + * + * @return string + */ + protected function get_slug() { + + return 'wc-' . $this->get_plugin()->get_id_dasherized() . '-setup'; + } + + + /** + * Gets the plugin instance. + * + * @since 5.2.2 + * + * @return Framework\SV_WC_Plugin|Framework\SV_WC_Payment_Gateway_Plugin + */ + protected function get_plugin() { + + return $this->plugin; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/Abstract_Cacheable_API_Base.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/Abstract_Cacheable_API_Base.php new file mode 100644 index 0000000..507bb2c --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/Abstract_Cacheable_API_Base.php @@ -0,0 +1,273 @@ +is_request_cacheable() && ! $this->get_request()->should_refresh() && $response = $this->load_response_from_cache() ) { + + $this->response_loaded_from_cache = true; + + return $response; + } + + return parent::do_remote_request( $request_uri, $request_args ); + } + + + /** + * Handle and parse the response + * + * @since 5.10.10 + * + * @param array|\WP_Error $response response data + * @throws SV_WC_API_Exception network issues, timeouts, API errors, etc + * @return SV_WC_API_Request|object request class instance that implements SV_WC_API_Request + */ + protected function handle_response( $response ) { + + parent::handle_response( $response ); + + // cache the response + if ( ! $this->is_response_loaded_from_cache() && $this->is_request_cacheable() ) { + + $this->save_response_to_cache( $response ); + } + + return $this->response; // this param is set by the parent method + } + + + /** + * Resets the API response members to their default values. + * + * @since 5.10.10 + */ + protected function reset_response() { + + $this->response_loaded_from_cache = false; + + parent::reset_response(); + } + + + /** + * Gets the request transient key for the current plugin and request data. + * + * Request transients can be disabled by using the filter below. + * + * @since 5.10.10 + * + * @return string transient key + */ + protected function get_request_transient_key() : string { + + // ex: wc__ + return sprintf( 'wc_%s_api_response_%s', $this->get_plugin()->get_id(), md5( implode( '_', [ + $this->get_request_uri(), + $this->get_request_body(), + $this->get_request_cache_lifetime(), + ] ) ) ); + } + + + /** + * Checks whether the current request is cacheable. + * + * @since 5.10.10 + * + * @return bool + */ + protected function is_request_cacheable() : bool { + + if ( ! in_array( Cacheable_Request_Trait::class, class_uses( $this->get_request() ), true ) ) { + return false; + } + + /** + * Filters whether the API request is cacheable. + * + * Allows actors to disable API request caching when a request is normally cacheable. This may be useful + * primarily for debugging situations. + * + * Note: this filter is only applied if the request is originally cacheable, in order to prevent issues when + * a non-cacheable request is accidentally flagged as cacheable. + * + * @since 5.10.10 + * + * @param bool $is_cacheable whether the request is cacheable + * @param SV_WC_API_Request $request the request instance + */ + return (bool) apply_filters( 'wc_plugin_' . $this->get_plugin()->get_id() . '_api_request_is_cacheable', true, $this->get_request() ); + } + + + /** + * Gets the cache lifetime for the current request. + * + * @since 5.10.10 + * + * @return int + */ + protected function get_request_cache_lifetime() : int { + + /** + * Filters API request cache lifetime. + * + * Allows actors to override cache lifetime for cacheable API requests. This may be useful for debugging + * API requests by temporarily setting short cache timeouts. + * + * @since 5.10.10 + * + * @param int $lifetime cache lifetime in seconds, 0 = unlimited + * @param SV_WC_API_Request $request the request instance + */ + return (int) apply_filters( 'wc_plugin_' . $this->get_plugin()->get_id() . '_api_request_cache_lifetime' , $this->get_request()->get_cache_lifetime(), $this->get_request() ); + } + + + + /** + * Determine whether the response was loaded from cache or not. + * + * @since 5.10.10 + * + * @return bool + */ + protected function is_response_loaded_from_cache() : bool { + + return $this->response_loaded_from_cache; + } + + + /** + * Loads the response for the current request from the cache, if available. + * + * @since 5.10.10 + * + * @return array|null + */ + protected function load_response_from_cache() { + + return get_transient( $this->get_request_transient_key() ); + } + + + /** + * Saves the response to cache. + * + * @since 5.10.10 + * + * @param array $response + */ + protected function save_response_to_cache( array $response ) { + + set_transient( $this->get_request_transient_key(), $response, $this->get_request_cache_lifetime() ); + } + + + /** + * Gets the response data for broadcasting the request. + * + * Adds a flag to the response data indicating whether the response was loaded from cache. + * + * @since 5.10.10 + * + * @return array + */ + protected function get_request_data_for_broadcast() : array { + + $request_data = parent::get_request_data_for_broadcast(); + + if ( $this->is_request_cacheable() ) { + $request_data = [ + 'force_refresh' => $this->get_request()->should_refresh(), + 'should_cache' => $this->get_request()->should_cache(), + ] + $request_data; + } + + return $request_data; + } + + + /** + * Gets the response data for broadcasting the request. + * + * Adds a flag to the response data indicating whether the response was loaded from cache. + * + * @since 5.10.10 + * + * @return array + */ + protected function get_response_data_for_broadcast() : array { + + $response_data = parent::get_response_data_for_broadcast(); + + if ( $this->is_request_cacheable() ) { + $response_data = [ 'from_cache' => $this->is_response_loaded_from_cache() ] + $response_data; + } + + return $response_data; + } + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-request.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-request.php new file mode 100644 index 0000000..1117d77 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-request.php @@ -0,0 +1,135 @@ +method; + } + + + /** + * Get the request path. + * + * @since 4.3.0 + * @see SV_WC_API_Request::get_path() + * @return string + */ + public function get_path() { + return $this->path; + } + + + /** + * Get the request parameters. + * + * @since 4.3.0 + * @see SV_WC_API_Request::get_params() + * @return array + */ + public function get_params() { + return $this->params; + } + + + /** + * Get the request data. + * + * @since 4.5.0 + * @return array + */ + public function get_data() { + return $this->data; + } + + + /** API Helper Methods ******************************************************/ + + + /** + * Get the string representation of this request. + * + * @since 4.3.0 + * @see SV_WC_API_Request::to_string() + * @return string + */ + public function to_string() { + + $data = $this->get_data(); + + return ! empty( $data ) ? json_encode( $data ) : ''; + } + + + /** + * Get the string representation of this request with any and all sensitive elements masked + * or removed. + * + * @since 4.3.0 + * @see SV_WC_API_Request::to_string_safe() + * @return string + */ + public function to_string_safe() { + + return $this->to_string(); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-response.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-response.php new file mode 100644 index 0000000..22cfc0b --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-json-response.php @@ -0,0 +1,105 @@ +raw_response_json = $raw_response_json; + + $this->response_data = json_decode( $raw_response_json ); + } + + + /** + * Magic accessor for response data attributes + * + * @since 4.3.0 + * @param string $name The attribute name to get. + * @return mixed The attribute value + */ + public function __get( $name ) { + + // accessing the response_data object indirectly via attribute (useful when it's a class) + return isset( $this->response_data->$name ) ? $this->response_data->$name : null; + } + + + /** + * Get the string representation of this response. + * + * @since 4.3.0 + * @see SV_WC_API_Response::to_string() + * @return string + */ + public function to_string() { + + return $this->raw_response_json; + } + + + /** + * Get the string representation of this response with any and all sensitive elements masked + * or removed. + * + * @since 4.3.0 + * @see SV_WC_API_Response::to_string_safe() + * @return string + */ + public function to_string_safe() { + + return $this->to_string(); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-request.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-request.php new file mode 100644 index 0000000..6e942ab --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-request.php @@ -0,0 +1,200 @@ +method; + } + + + /** + * Get the path for this request. + * + * @since 4.3.0 + * @see SV_WC_API_Request::get_path() + * @return string + */ + public function get_path() { + return $this->path; + } + + + /** + * Get the request parameters. + * + * @since 4.5.0 + * @return array + */ + public function get_params() { + return $this->params; + } + + + /** + * Convert the request data into XML. + * + * @since 4.3.0 + * @return string + */ + protected function to_xml() { + + if ( ! empty( $this->request_xml ) ) { + return $this->request_xml; + } + + $this->xml = new \XMLWriter(); + + // Create XML document in memory + $this->xml->openMemory(); + + // Set XML version & encoding + $this->xml->startDocument( '1.0', 'UTF-8' ); + + $request_data = $this->get_data(); + + SV_WC_Helper::array_to_xml( $this->xml, $this->get_root_element(), $request_data[ $this->get_root_element() ] ); + + $this->xml->endDocument(); + + return $this->request_xml = $this->xml->outputMemory(); + } + + + /** + * Gets the request data to be converted to XML. + * + * @since 5.0.0 + * @return array + */ + public function get_data() { + + return $this->request_data; + } + + + /** + * Get the string representation of this request + * + * @since 4.3.0 + * @see SV_WC_API_Request::to_string() + * @return string + */ + public function to_string() { + + return $this->to_xml(); + } + + + /** + * Get the string representation of this request with any and all sensitive elements masked + * or removed. + * + * @since 4.3.0 + * @see SV_WC_API_Request::to_string_safe() + * @return string + */ + public function to_string_safe() { + + return $this->prettify_xml( $this->to_string() ); + } + + + /** + * Helper method for making XML pretty, suitable for logging or rendering + * + * @since 4.3.0 + * @param string $xml_string ugly XML string + * @return string + */ + public function prettify_xml( $xml_string ) { + + $dom = new \DOMDocument(); + + // suppress errors for invalid XML syntax issues + if ( @$dom->loadXML( $xml_string ) ) { + $dom->formatOutput = true; + $xml_string = $dom->saveXML(); + } + + return $xml_string; + } + + + /** + * Concrete classes must implement this method to return the root element + * for the XML document + * + * @since 4.3.0 + * @return string + */ + abstract protected function get_root_element(); + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-response.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-response.php new file mode 100644 index 0000000..23597a4 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/abstract-sv-wc-api-xml-response.php @@ -0,0 +1,138 @@ +raw_response_xml = $raw_response_xml; + + // LIBXML_NOCDATA ensures that any XML fields wrapped in [CDATA] will be included as text nodes + $this->response_xml = new \SimpleXMLElement( $raw_response_xml, LIBXML_NOCDATA ); + + /** + * workaround to convert the horrible data structure that SimpleXMLElement returns + * and provide a nice array of stdClass objects. Note there is some fidelity lost + * in the conversion (such as attributes), but implementing classes can access + * the response_xml member directly to retrieve them as needed. + */ + $this->response_data = json_decode( json_encode( $this->response_xml ) ); + } + + + /** + * Magic method for getting XML element data. Note the response data has + * already been casted into simple data types (string,int,array) and does not + * require further casting in order to use. + * + * @since 4.3.0 + * @param string $key + * @return mixed + */ + public function __get( $key ) { + + if ( ! isset( $this->response_data->$key ) ) { + return null; + } + + // array cast & empty check prevents fataling on empty stdClass objects + $array = (array) $this->response_data->$key; + + if ( empty( $array ) ) { + return null; + } + + return $this->response_data->$key; + } + + + /** + * Get the string representation of this response. + * + * @since 4.3.0 + * @return string + */ + public function to_string() { + + $response = $this->raw_response_xml; + + $dom = new \DOMDocument(); + + // suppress errors for invalid XML syntax issues + if ( @$dom->loadXML( $response ) ) { + $dom->formatOutput = true; + $response = $dom->saveXML(); + } + + return $response; + } + + + /** + * Get the string representation of this response with any and all sensitive elements masked + * or removed. + * + * @since 4.3.0 + * @see SV_WC_API_Response::to_string_safe() + * @return string + */ + public function to_string_safe() { + + return $this->to_string(); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-base.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-base.php new file mode 100644 index 0000000..2fd0e2e --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-base.php @@ -0,0 +1,867 @@ +reset_response(); + + // save the request object + $this->request = $request; + + $start_time = microtime( true ); + + // if this API requires TLS v1.2, force it + if ( $this->get_plugin()->require_tls_1_2() ) { + add_action( 'http_api_curl', array( $this, 'set_tls_1_2_request' ), 10, 3 ); + } + + // perform the request + $response = $this->do_remote_request( $this->get_request_uri(), $this->get_request_args() ); + + // calculate request duration + $this->request_duration = round( microtime( true ) - $start_time, 5 ); + + try { + + // parse & validate response + $response = $this->handle_response( $response ); + + } catch ( SV_WC_Plugin_Exception $e ) { + + // alert other actors that a request has been made + $this->broadcast_request(); + + throw $e; + } + + return $response; + } + + + /** + * Simple wrapper for wp_remote_request() so child classes can override this + * and provide their own transport mechanism if needed, e.g. a custom + * cURL implementation + * + * @since 2.2.0 + * + * @param string $request_uri + * @param string $request_args + * @return array|\WP_Error + */ + protected function do_remote_request( $request_uri, $request_args ) { + + return wp_safe_remote_request( $request_uri, $request_args ); + } + + + /** + * Handle and parse the response + * + * @since 2.2.0 + * @param array|\WP_Error $response response data + * @throws SV_WC_API_Exception network issues, timeouts, API errors, etc + * @return SV_WC_API_Request|object request class instance that implements SV_WC_API_Request + */ + protected function handle_response( $response ) { + + // check for WP HTTP API specific errors (network timeout, etc) + if ( is_wp_error( $response ) ) { + throw new SV_WC_API_Exception( $response->get_error_message(), (int) $response->get_error_code() ); + } + + // set response data + $this->response_code = wp_remote_retrieve_response_code( $response ); + $this->response_message = wp_remote_retrieve_response_message( $response ); + $this->raw_response_body = wp_remote_retrieve_body( $response ); + + $response_headers = wp_remote_retrieve_headers( $response ); + + // WP 4.6+ returns an object + if ( is_object( $response_headers ) ) { + $response_headers = $response_headers->getAll(); + } + + $this->response_headers = $response_headers; + + // allow child classes to validate response prior to parsing -- this is useful + // for checking HTTP status codes, etc. + $this->do_pre_parse_response_validation(); + + // parse the response body and tie it to the request + $this->response = $this->get_parsed_response( $this->raw_response_body ); + + // allow child classes to validate response after parsing -- this is useful + // for checking error codes/messages included in a parsed response + $this->do_post_parse_response_validation(); + + // fire do_action() so other actors can act on request/response data, + // primarily used for logging + $this->broadcast_request(); + + return $this->response; + } + + + /** + * Allow child classes to validate a response prior to instantiating the + * response object. Useful for checking response codes or messages, e.g. + * throw an exception if the response code is not 200. + * + * A child class implementing this method should simply return true if the response + * processing should continue, or throw a \SV_WC_API_Exception with a + * relevant error message & code to stop processing. + * + * Note: Child classes *must* sanitize the raw response body before throwing + * an exception, as it will be included in the broadcast_request() method + * which is typically used to log requests. + * + * @since 2.2.0 + */ + protected function do_pre_parse_response_validation() { + // stub method + } + + + /** + * Allow child classes to validate a response after it has been parsed + * and instantiated. This is useful for check error codes or messages that + * exist in the parsed response. + * + * A child class implementing this method should simply return true if the response + * processing should continue, or throw a \SV_WC_API_Exception with a + * relevant error message & code to stop processing. + * + * Note: Response body sanitization is handled automatically + * + * @since 2.2.0 + */ + protected function do_post_parse_response_validation() { + // stub method + } + + + /** + * Return the parsed response object for the request + * + * @since 2.2.0 + * @param string $raw_response_body + * @return object|SV_WC_API_Request response class instance which implements SV_WC_API_Request + */ + protected function get_parsed_response( $raw_response_body ) { + + $handler_class = $this->get_response_handler(); + + return new $handler_class( $raw_response_body ); + } + + + /** + * Alert other actors that a request has been performed. This is primarily used + * for request logging. + * + * @since 2.2.0 + */ + protected function broadcast_request() { + + $request_data = $this->get_request_data_for_broadcast(); + $response_data = $this->get_response_data_for_broadcast(); + + /** + * API Base Request Performed Action. + * + * Fired when an API request is performed via this base class. Plugins can + * hook into this to log request/response data. + * + * Note: request and response data arrays may contain additional, undocumented keys provided by the implementing plugin. + * + * @since 2.2.0 + * @param array $request_data { + * @type string $method request method, e.g. POST + * @type string $uri request URI + * @type string $user-agent + * @type string $headers request headers + * @type string $body request body + * @type string $duration in seconds + * } + * @param array $response data { + * @type string $code response HTTP code + * @type string $message response message + * @type string $headers response HTTP headers + * @type string $body response body + * } + * @param SV_WC_API_Base $this instance + */ + do_action( 'wc_' . $this->get_api_id() . '_api_request_performed', $request_data, $response_data, $this ); + } + + + /** + * Reset the API response members to their + * + * @since 1.0.0 + */ + protected function reset_response() { + + $this->response_code = null; + $this->response_message = null; + $this->response_headers = null; + $this->raw_response_body = null; + $this->response = null; + $this->request_duration = null; + } + + + /** Request Getters *******************************************************/ + + + /** + * Get the request URI + * + * @since 2.2.0 + * @return string + */ + protected function get_request_uri() { + + $uri = $this->request_uri . $this->get_request_path(); + + // append any query params to the URL when necessary + if ( $query = $this->get_request_query() ) { + + $url_parts = parse_url( $uri ); + + // if the URL already has some query params, add to them + if ( ! empty( $url_parts['query'] ) ) { + $query = '&' . $query; + } else { + $query = '?' . $query; + } + + $uri = untrailingslashit( $uri ) . $query; + } + + /** + * Request URI Filter. + * + * Allow actors to filter the request URI. Note that child classes can override + * this method, which means this filter may be invoked prior to the overridden + * method. + * + * @since 4.1.0 + * + * @param string $uri current request URI + * @param SV_WC_API_Base class instance + */ + return apply_filters( 'wc_' . $this->get_api_id() . '_api_request_uri', $uri, $this ); + } + + + /** + * Gets the request path. + * + * @since 4.5.0 + * @return string + */ + protected function get_request_path() { + + return ( $this->get_request() ) ? $this->get_request()->get_path() : ''; + } + + + /** + * Gets the request URL query. + * + * @since 4.5.0 + * + * @return string + */ + protected function get_request_query() { + + $query = ''; + $request = $this->get_request(); + + if ( $request && in_array( strtoupper( $this->get_request_method() ), array( 'GET', 'HEAD' ), true ) ) { + + $params = $request->get_params(); + + if ( ! empty( $params ) ) { + $query = http_build_query( $params, '', '&' ); + } + } + + return $query; + } + + + /** + * Get the request arguments in the format required by wp_remote_request() + * + * @since 2.2.0 + * + * @return array + */ + protected function get_request_args() { + + $args = array( + 'method' => $this->get_request_method(), + 'timeout' => MINUTE_IN_SECONDS, + 'redirection' => 0, + 'httpversion' => $this->get_request_http_version(), + 'sslverify' => true, + 'blocking' => true, + 'user-agent' => $this->get_request_user_agent(), + 'headers' => $this->get_request_headers(), + 'body' => $this->get_request_body(), + 'cookies' => array(), + ); + + /** + * Request arguments. + * + * Allow other actors to filter the request arguments. Note that + * child classes can override this method, which means this filter may + * not be invoked, or may be invoked prior to the overridden method + * + * @since 2.2.0 + * @param array $args request arguments + * @param SV_WC_API_Base class instance + */ + return apply_filters( 'wc_' . $this->get_api_id() . '_http_request_args', $args, $this ); + } + + + /** + * Get the request method, POST by default + * + * @since 2.2.0 + * @return string + */ + protected function get_request_method() { + // if the request object specifies the method to use, use that, otherwise use the API default + return $this->get_request() && $this->get_request()->get_method() ? $this->get_request()->get_method() : $this->request_method; + } + + + /** + * Gets the request body. + * + * @since 4.5.0 + * @return string + */ + protected function get_request_body() { + + // GET & HEAD requests don't support a body + if ( in_array( strtoupper( $this->get_request_method() ), array( 'GET', 'HEAD' ) ) ) { + return ''; + } + + return ( $this->get_request() && $this->get_request()->to_string() ) ? $this->get_request()->to_string() : ''; + } + + + /** + * Gets the sanitized request body, for logging. + * + * @since 4.5.0 + * @return string + */ + protected function get_sanitized_request_body() { + + // GET & HEAD requests don't support a body + if ( in_array( strtoupper( $this->get_request_method() ), array( 'GET', 'HEAD' ) ) ) { + return ''; + } + + return ( $this->get_request() && $this->get_request()->to_string_safe() ) ? $this->get_request()->to_string_safe() : ''; + } + + + /** + * Get the request HTTP version, 1.1 by default + * + * @since 2.2.0 + * @return string + */ + protected function get_request_http_version() { + + return $this->request_http_version; + } + + + /** + * Get the request headers + * + * @since 2.2.0 + * @return array + */ + protected function get_request_headers() { + return $this->request_headers; + } + + + /** + * Get sanitized request headers suitable for logging, stripped of any + * confidential information + * + * The `Authorization` header is sanitized automatically. + * + * Child classes that implement any custom authorization headers should + * override this method to perform sanitization. + * + * @since 2.2.0 + * @return array + */ + protected function get_sanitized_request_headers() { + + $headers = $this->get_request_headers(); + + if ( ! empty( $headers['Authorization'] ) ) { + $headers['Authorization'] = str_repeat( '*', strlen( $headers['Authorization'] ) ); + } + + return $headers; + } + + + /** + * Get the request user agent, defaults to: + * + * Dasherized-Plugin-Name/Plugin-Version (WooCommerce/WC-Version; WordPress/WP-Version) + * + * @since 2.2.0 + * @return string + */ + protected function get_request_user_agent() { + + return sprintf( '%s/%s (WooCommerce/%s; WordPress/%s)', str_replace( ' ', '-', $this->get_plugin()->get_plugin_name() ), $this->get_plugin()->get_version(), WC_VERSION, $GLOBALS['wp_version'] ); + } + + + /** + * Get the request duration in seconds, rounded to the 5th decimal place + * + * @since 2.2.0 + * @return string + */ + protected function get_request_duration() { + return $this->request_duration; + } + + + /** + * Gets the request data for broadcasting the request. + * + * Overriding this method allows child classes to customize the request data when broadcasting the request. + * + * @since 5.10.10 + * + * @return array + */ + protected function get_request_data_for_broadcast() : array { + + return [ + 'method' => $this->get_request_method(), + 'uri' => $this->get_request_uri(), + 'user-agent' => $this->get_request_user_agent(), + 'headers' => $this->get_sanitized_request_headers(), + 'body' => $this->get_sanitized_request_body(), + 'duration' => $this->get_request_duration() . 's', // seconds + ]; + } + + + /** Response Getters ******************************************************/ + + + /** + * Get the response handler class name + * + * @since 2.2.0 + * @return string + */ + protected function get_response_handler() { + return $this->response_handler; + } + + + /** + * Get the response code + * + * @since 2.2.0 + * @return string + */ + protected function get_response_code() { + return $this->response_code; + } + + + /** + * Get the response message + * + * @since 2.2.0 + * @return string + */ + protected function get_response_message() { + return $this->response_message; + } + + + /** + * Get the response headers + * + * @since 2.2.0 + * @return array + */ + protected function get_response_headers() { + return $this->response_headers; + } + + + /** + * Get the raw response body, prior to any parsing or sanitization + * + * @since 2.2.0 + * @return string + */ + protected function get_raw_response_body() { + return $this->raw_response_body; + } + + + /** + * Get the sanitized response body, provided by the response class + * to_string_safe() method + * + * @since 2.2.0 + * @return string|null + */ + protected function get_sanitized_response_body() { + return is_callable( array( $this->get_response(), 'to_string_safe' ) ) ? $this->get_response()->to_string_safe() : null; + } + + + /** + * Gets the response data for broadcasting the request. + * + * Overriding this method allows child classes to customize the response data when broadcasting the request. + * + * @since 5.10.10 + * + * @return array + * @return array + */ + protected function get_response_data_for_broadcast() : array + { + return [ + 'code' => $this->get_response_code(), + 'message' => $this->get_response_message(), + 'headers' => $this->get_response_headers(), + 'body' => $this->get_sanitized_response_body() ?: $this->get_raw_response_body(), + ]; + } + + + /** Misc Getters ******************************************************/ + + + /** + * Returns the most recent request object. + * + * @since 2.2.0 + * + * @return SV_WC_API_Request|object the most recent request object + */ + public function get_request() { + + return $this->request; + } + + + /** + * Returns the most recent response object. + * + * @since 2.2.0 + * + * @return SV_WC_API_Response|object the most recent response object + */ + public function get_response() { + + return $this->response; + } + + + /** + * Get the ID for the API, used primarily to namespace the action name + * for broadcasting requests + * + * @since 2.2.0 + * @return string + */ + protected function get_api_id() { + + return $this->get_plugin()->get_id(); + } + + + /** + * Return a new request object + * + * Child classes must implement this to return an object that implements + * \SV_WC_API_Request which should be used in the child class API methods + * to build the request. The returned SV_WC_API_Request should be passed + * to self::perform_request() by your concrete API methods + * + * @since 2.2.0 + * + * @param array $args optional request arguments + * @return SV_WC_API_Request|object + */ + abstract protected function get_new_request( $args = array() ); + + + /** + * Return the plugin class instance associated with this API + * + * Child classes must implement this to return their plugin class instance + * + * This is used for defining the plugin ID used in filter names, as well + * as the plugin name used for the default user agent. + * + * @since 2.2.0 + * + * @return SV_WC_Plugin + */ + abstract protected function get_plugin(); + + + /** Setters ***************************************************************/ + + + /** + * Set a request header + * + * @since 2.2.0 + * @param string $name header name + * @param string $value header value + * @return string + */ + protected function set_request_header( $name, $value ) { + + $this->request_headers[ $name ] = $value; + } + + + /** + * Set multiple request headers at once + * + * @since 4.3.0 + * @param array $headers + */ + protected function set_request_headers( array $headers ) { + + foreach ( $headers as $name => $value ) { + + $this->request_headers[ $name ] = $value; + } + } + + + /** + * Set HTTP basic auth for the request + * + * Since 2.2.0 + * @param string $username + * @param string $password + */ + protected function set_http_basic_auth( $username, $password ) { + + $this->request_headers['Authorization'] = sprintf( 'Basic %s', base64_encode( "{$username}:{$password}" ) ); + } + + + /** + * Set the Content-Type request header + * + * @since 2.2.0 + * @param string $content_type + */ + protected function set_request_content_type_header( $content_type ) { + $this->request_headers['content-type'] = $content_type; + } + + + /** + * Set the Accept request header + * + * @since 2.2.0 + * @param string $type the request accept type + */ + protected function set_request_accept_header( $type ) { + $this->request_headers['accept'] = $type; + } + + + /** + * Set the response handler class name. This class will be instantiated + * to parse the response for the request. + * + * Note the class should implement SV_WC_API + * + * @since 2.2.0 + * + * @param string $handler handle class name + */ + protected function set_response_handler( $handler ) { + + $this->response_handler = $handler; + } + + + /** + * Maybe force TLS v1.2 requests. + * + * @since 4.4.0 + * + * @param resource $handle the cURL handle returned by curl_init() (passed by reference) + * @param array $r the HTTP request arguments + * @param $url string the request URL + */ + public function set_tls_1_2_request( $handle, $r, $url ) { + + if ( ! SV_WC_Helper::str_starts_with( $url, 'https://' ) ) { + return; + } + + curl_setopt( $handle, CURLOPT_SSLVERSION, 6 ); + } + + + /** + * Determines if TLS v1.2 is required for API requests. + * + * @since 4.4.0 + * @deprecated 5.5.2 + * + * @return bool + */ + public function require_tls_1_2() { + + wc_deprecated_function( __METHOD__, '5.5.2', 'SV_WC_Plugin::require_tls_1_2()' ); + + return $this->get_plugin()->require_tls_1_2(); + } + + + /** + * Determines if TLS 1.2 is available. + * + * @since 4.6.5 + * + * @return bool + */ + public function is_tls_1_2_available() { + + /** + * Filters whether TLS 1.2 is available. + * + * @since 4.7.1 + * + * @param bool $is_available whether TLS 1.2 is available + * @param SV_WC_API_Base $api API class instance + */ + return (bool) apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_api_is_tls_1_2_available', $this->get_plugin()->is_tls_1_2_available(), $this ); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-exception.php b/vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-exception.php new file mode 100644 index 0000000..733a2e3 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/api/class-sv-wc-api-exception.php @@ -0,0 +1,38 @@ +cache_lifetime = $lifetime; + + return $this; + } + + + /** + * Gets the cache lifetime for this request. + * + * @since 5.10.10 + * + * @return int + */ + public function get_cache_lifetime() : int { + + return $this->cache_lifetime; + } + + + /** + * Sets whether a fresh request should be attempted, regardless if a cached response is available. + * + * @since 5.10.10 + * + * @param bool $value whether to force a fresh request, or not + * @return self + */ + public function set_force_refresh( bool $value ) { + + $this->force_refresh = $value; + + return $this; + } + + + /** + * Determines whether a fresh request should be attempted. + * + * @since 5.10.10 + * + * @return bool + */ + public function should_refresh() : bool { + + return $this->force_refresh; + } + + + /** + * Sets whether the request's response should be stored in cache. + * + * @since 5.10.10 + * + * @param bool $value whether to cache the request, or not + * @return self + */ + public function set_should_cache( bool $value ) { + + $this->should_cache = $value; + + return $this; + } + + + /** + * Determines whether the request's response should be stored in cache. + * + * @since 5.10.10 + * + * @return bool + */ + public function should_cache() : bool { + + return $this->should_cache; + } + + + /** + * Bypasses caching for this request completely. + * + * When called, sets the `force_refresh` flag to true and `should_cache` flag to false + * + * @since 5.10.10 + * + * @return self + */ + public function bypass_cache() { + + $this->set_force_refresh( true ); + $this->set_should_cache( false ); + + return $this; + } + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/assets/css/admin/sv-wc-plugin-admin-setup-wizard.min.css b/vendor/skyverge/wc-plugin-framework/woocommerce/assets/css/admin/sv-wc-plugin-admin-setup-wizard.min.css new file mode 100644 index 0000000..50d350d --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/assets/css/admin/sv-wc-plugin-admin-setup-wizard.min.css @@ -0,0 +1 @@ +h1#wc-logo.sv-wc-plugin-logo{font-size:28px;font-weight:bold}h1#wc-logo.sv-wc-plugin-logo a{color:#444444;text-decoration:none}h1#wc-logo.sv-wc-plugin-logo a:hover{color:#222222;text-decoration:none}.sv-wc-plugin-admin-setup-content .error{background:#dc3232;border-radius:5px;color:#fff;padding:1em}.sv-wc-plugin-admin-setup-content .error a{color:#fff;text-decoration:none}.sv-wc-plugin-admin-setup-content .error a:hover{text-decoration:underline}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control{margin-bottom:20px}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control label{color:#666;display:inline-block;font-size:15px;font-weight:500;margin-top:.85em;margin-bottom:.5em}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control input[type="text"],.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control input[type="number"],.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control input[type="password"],.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control select{background-color:#fff;border:1px solid #ddd;border-radius:4px;color:#444;display:inline-block;font-size:16px;height:30px;padding:0 24px 0 8px;width:calc(100% - 8px - 24px - 2px)}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control select{width:100%}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control textarea{background-color:#fff;border:1px solid #ddd;border-radius:4px;color:#444;font-size:16px;padding:10px}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control .description{color:#888;font-size:13px;margin:5px 0 0}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle{display:flex;flex-wrap:nowrap;justify-content:space-between;padding:0;border-bottom:1px solid #eee;color:#666;align-items:top}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle:last-child{border-bottom:0}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .name{flex-basis:0;min-width:160px;text-align:center;font-weight:bold;align-self:stretch;display:flex;align-items:baseline}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .content{flex-grow:1;padding:20px}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .content p{margin-bottom:1em}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .content p:last-child{margin-bottom:0}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .enable{flex-basis:0;min-width:75px;text-align:center;cursor:pointer;padding:2em 0;position:relative;max-height:1.5em;align-self:flex-start}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .toggle{height:16px;width:32px;border:2px solid #935687;background-color:#935687;display:inline-block;text-indent:-9999px;border-radius:10em;position:relative}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .toggle input[type=checkbox]{display:none}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .toggle:before{content:"";display:block;width:16px;height:16px;background:#fff;position:absolute;top:0;right:0;border-radius:100%}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .toggle.disabled{border-color:#999;background-color:#999}.sv-wc-plugin-admin-setup-content .sv-wc-plugin-admin-setup-control.toggle .toggle.disabled:before{right:auto;left:0} \ No newline at end of file diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/assets/images/ajax-loader.gif b/vendor/skyverge/wc-plugin-framework/woocommerce/assets/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..e01a70fb0d871ce6f10845968dced3426a1626a5 GIT binary patch literal 885 zcmZ?wbhEHb6krfw_{_v`@7}%Y>gv6F_da{}tfi%;r>E!IwQEzROgVb==+dQ2*REZ= zb?a6JB%t`8+s`#5*x50_)kx2PnGq+Z`nSqHxhmC=efrWvOfq_|&Bh*3gh~v?g zy%w*%Z+FK}hpA#=&|v|p;sB{)QJUbPd0~nwOKGV__#$0#MxNAF>s~WV>7EudvrJQ} zLeWW*5o$P48xzn59w203R`S?o#njX5kf_qcR(NvFTy>trNUId~jLa#4ceV!Qvh*Y} zLA5b3=s;Y=0klm~;DqPVK$B)ct4otFvNBny9#oWdO!7LEvFC)vo`#|+`78*ZFfyXt}?ek?B z0u2Y4*(e@S@KA96$JcUmfv_=$bn#Q>!@Vh)ZSzf24s`fRpO}<58%LliIA(<^ig
    $jvFons<1>uj;7@plugin = $plugin; + + // render any admin notices, delayed notices, and + add_action( 'admin_notices', array( $this, 'render_admin_notices' ), 15 ); + add_action( 'admin_footer', array( $this, 'render_delayed_admin_notices' ), 15 ); + add_action( 'admin_footer', array( $this, 'render_admin_notice_js' ), 20 ); + + // AJAX handler to dismiss any warning/error notices + add_action( 'wp_ajax_wc_plugin_framework_' . $this->get_plugin()->get_id() . '_dismiss_notice', array( $this, 'handle_dismiss_notice' ) ); + } + + + /** + * Adds the given $message as a dismissible notice identified by $message_id, + * unless the notice has been dismissed, or we're on the plugin settings page + * + * @since 3.0.0 + * @param string $message the notice message to display + * @param string $message_id the message id + * @param array $params { + * Optional parameters. + * + * @type bool $dismissible If the notice should be dismissible + * @type bool $always_show_on_settings If the notice should be forced to display on the + * plugin settings page, regardless of `$dismissible`. + * @type string $notice_class Additional classes for the notice. + * } + */ + public function add_admin_notice( $message, $message_id, $params = array() ) { + + $params = wp_parse_args( $params, array( + 'dismissible' => true, + 'always_show_on_settings' => true, + 'notice_class' => 'updated', + ) ); + + if ( $this->should_display_notice( $message_id, $params ) ) { + $this->admin_notices[ $message_id ] = array( + 'message' => $message, + 'rendered' => false, + 'params' => $params, + ); + } + } + + + /** + * Returns true if the identified notice hasn't been cleared, or we're on + * the plugin settings page (where notices are always displayed) + * + * @since 3.0.0 + * @param string $message_id the message id + * @param array $params { + * Optional parameters. + * + * @type bool $dismissible If the notice should be dismissible + * @type bool $always_show_on_settings If the notice should be forced to display on the + * plugin settings page, regardless of `$dismissible`. + * } + * @return bool + */ + public function should_display_notice( $message_id, $params = array() ) { + + // bail out if user is not a shop manager + if ( ! current_user_can( 'manage_woocommerce' ) ) { + return false; + } + + $params = wp_parse_args( $params, array( + 'dismissible' => true, + 'always_show_on_settings' => true, + ) ); + + // if the notice is always shown on the settings page, and we're on the settings page + if ( $params['always_show_on_settings'] && $this->get_plugin()->is_plugin_settings() ) { + return true; + } + + // non-dismissible, always display + if ( ! $params['dismissible'] ) { + return true; + } + + // dismissible: display if notice has not been dismissed + return ! $this->is_notice_dismissed( $message_id ); + } + + + /** + * Render any admin notices, as well as the admin notice placeholder + * + * @since 3.0.0 + * @param boolean $is_visible true if the notices should be immediately visible, false otherwise + */ + public function render_admin_notices( $is_visible = true ) { + + // default for actions + if ( ! is_bool( $is_visible ) ) { + $is_visible = true; + } + + foreach ( $this->admin_notices as $message_id => $message_data ) { + if ( ! $message_data['rendered'] ) { + $message_data['params']['is_visible'] = $is_visible; + $this->render_admin_notice( $message_data['message'], $message_id, $message_data['params'] ); + $this->admin_notices[ $message_id ]['rendered'] = true; + } + } + + if ( $is_visible && ! self::$admin_notice_placeholder_rendered ) { + // placeholder for moving delayed notices up into place + echo '
    '; + self::$admin_notice_placeholder_rendered = true; + } + + } + + + /** + * Render any delayed admin notices, which have not yet already been rendered + * + * @since 3.0.0 + */ + public function render_delayed_admin_notices() { + $this->render_admin_notices( false ); + } + + + /** + * Render a single admin notice + * + * @since 3.0.0 + * @param string $message the notice message to display + * @param string $message_id the message id + * @param array $params { + * Optional parameters. + * + * @type bool $dismissible If the notice should be dismissible + * @type bool $is_visible If the notice should be immediately visible + * @type bool $always_show_on_settings If the notice should be forced to display on the + * plugin settings page, regardless of `$dismissible`. + * @type string $notice_class Additional classes for the notice. + * } + */ + public function render_admin_notice( $message, $message_id, $params = array() ) { + + $params = wp_parse_args( $params, array( + 'dismissible' => true, + 'is_visible' => true, + 'always_show_on_settings' => true, + 'notice_class' => 'updated', + ) ); + + $classes = array( + 'notice', + 'js-wc-plugin-framework-admin-notice', + $params['notice_class'], + ); + + // maybe make this notice dismissible + // uses a WP core class which handles the markup and styling + if ( $params['dismissible'] && ( ! $params['always_show_on_settings'] || ! $this->get_plugin()->is_plugin_settings() ) ) { + $classes[] = 'is-dismissible'; + } + + echo sprintf( + '

    %5$s

    ', + esc_attr( implode( ' ', $classes ) ), + esc_attr( $this->get_plugin()->get_id() ), + esc_attr( $message_id ), + ( ! $params['is_visible'] ) ? 'style="display:none;"' : '', + wp_kses_post( $message ) + ); + } + + + /** + * Render the javascript to handle the notice "dismiss" functionality + * + * @since 3.0.0 + */ + public function render_admin_notice_js() { + + // if there were no notices, or we've already rendered the js, there's nothing to do + if ( empty( $this->admin_notices ) || self::$admin_notice_js_rendered ) { + return; + } + + $plugin_slug = $this->get_plugin()->get_id_dasherized(); + + self::$admin_notice_js_rendered = true; + + ob_start(); + + ?> + ( function( $ ) { + + // log dismissed notices + $( '.js-wc-plugin-framework-admin-notice' ).on( 'click.wp-dismiss-notice', '.notice-dismiss', function( e ) { + + var $notice = $( this ).closest( '.js-wc-plugin-framework-admin-notice' ); + + log_dismissed_notice( + $( $notice ).data( 'plugin-id' ), + $( $notice ).data( 'message-id' ) + ); + + } ); + + // Log and hide legacy notices + $( 'a.js-wc-plugin-framework-notice-dismiss' ).click( function( e ) { + + e.preventDefault(); + + var $notice = $( this ).closest( '.js-wc-plugin-framework-admin-notice' ); + + log_dismissed_notice( + $( $notice ).data( 'plugin-id' ), + $( $notice ).data( 'message-id' ) + ); + + $( $notice ).fadeOut(); + + } ); + + function log_dismissed_notice( pluginID, messageID ) { + + $.get( + ajaxurl, + { + action: 'wc_plugin_framework_' + pluginID + '_dismiss_notice', + messageid: messageID + } + ); + } + + // move any delayed notices up into position .show(); + $( '.js-wc-plugin-framework-admin-notice:hidden' ).insertAfter( '.js-wc--admin-notice-placeholder' ).show(); + + } ) ( jQuery ); + get_dismissed_notices( $user_id ); + + $dismissed_notices[ $message_id ] = true; + + update_user_meta( $user_id, '_wc_plugin_framework_' . $this->get_plugin()->get_id() . '_dismissed_messages', $dismissed_notices ); + + /** + * Admin Notice Dismissed Action. + * + * Fired when a user dismisses an admin notice. + * + * @since 3.0.0 + * @param string $message_id notice identifier + * @param string|int $user_id + */ + do_action( 'wc_' . $this->get_plugin()->get_id(). '_dismiss_notice', $message_id, $user_id ); + } + + + /** + * Marks the identified admin notice as not dismissed for the identified user + * + * @since 3.0.0 + * @param string $message_id the message identifier + * @param int $user_id optional user identifier, defaults to current user + */ + public function undismiss_notice( $message_id, $user_id = null ) { + + if ( is_null( $user_id ) ) { + $user_id = get_current_user_id(); + } + + $dismissed_notices = $this->get_dismissed_notices( $user_id ); + + $dismissed_notices[ $message_id ] = false; + + update_user_meta( $user_id, '_wc_plugin_framework_' . $this->get_plugin()->get_id() . '_dismissed_messages', $dismissed_notices ); + } + + + /** + * Returns true if the identified admin notice has been dismissed for the + * given user + * + * @since 3.0.0 + * @param string $message_id the message identifier + * @param int $user_id optional user identifier, defaults to current user + * @return boolean true if the message has been dismissed by the admin user + */ + public function is_notice_dismissed( $message_id, $user_id = null ) { + + $dismissed_notices = $this->get_dismissed_notices( $user_id ); + + return isset( $dismissed_notices[ $message_id ] ) && $dismissed_notices[ $message_id ]; + } + + + /** + * Returns the full set of dismissed notices for the user identified by + * $user_id, for this plugin + * + * @since 3.0.0 + * @param int $user_id optional user identifier, defaults to current user + * @return array of message id to dismissed status (true or false) + */ + public function get_dismissed_notices( $user_id = null ) { + + if ( is_null( $user_id ) ) { + $user_id = get_current_user_id(); + } + + $dismissed_notices = get_user_meta( $user_id, '_wc_plugin_framework_' . $this->get_plugin()->get_id() . '_dismissed_messages', true ); + + if ( empty( $dismissed_notices ) ) { + return array(); + } else { + return $dismissed_notices; + } + } + + + /** AJAX methods ******************************************************/ + + + /** + * Dismiss the identified notice + * + * @since 3.0.0 + */ + public function handle_dismiss_notice() { + + $this->dismiss_notice( $_REQUEST['messageid'] ); + + } + + + /** Getter methods ******************************************************/ + + + /** + * Get the plugin + * + * @since 3.0.0 + * @return SV_WC_Plugin returns the plugin instance + */ + protected function get_plugin() { + return $this->plugin; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php new file mode 100644 index 0000000..fd4c127 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php @@ -0,0 +1,407 @@ +registered_plugins[] = array( 'version' => $version, 'plugin_name' => $plugin_name, 'path' => $path, 'callback' => $callback, 'args' => $args ); + } + + + /** + * Loads all registered framework plugins, first initializing the plugin + * framework by loading the highest versioned one. + * + * @since 2.0.0 + */ + public function load_framework_plugins() { + + // first sort the registered plugins by framework version + usort( $this->registered_plugins, array( $this, 'compare_frameworks' ) ); + + $loaded_framework = null; + + foreach ( $this->registered_plugins as $plugin ) { + + // load the first found (highest versioned) plugin framework class + if ( ! class_exists( 'SV_WC_Plugin' ) ) { + require_once( $this->get_plugin_path( $plugin['path'] ) . '/lib/skyverge/woocommerce/class-sv-wc-plugin.php' ); + $loaded_framework = $plugin; + + // the loaded plugin is always considered active (for the + // purposes of handling conflicts between this and other plugins + // with incompatible framework versions) + $this->active_plugins[] = $plugin; + } + + // if the loaded version of the framework has a backwards compatibility requirement + // which is not met by the current plugin add an admin notice and move on without + // loading the plugin + if ( ! empty( $loaded_framework['args']['backwards_compatible'] ) && version_compare( $loaded_framework['args']['backwards_compatible'], $plugin['version'], '>' ) ) { + + $this->incompatible_framework_plugins[] = $plugin; + + // next plugin + continue; + } + + // if a plugin defines a minimum WC version which is not met, render a notice and skip loading the plugin + if ( ! empty( $plugin['args']['minimum_wc_version'] ) && version_compare( $this->get_wc_version(), $plugin['args']['minimum_wc_version'], '<' ) ) { + + $this->incompatible_wc_version_plugins[] = $plugin; + + // next plugin + continue; + } + + // if a plugin defines a minimum WP version which is not met, render a notice and skip loading the plugin + if ( ! empty( $plugin['args']['minimum_wp_version'] ) && version_compare( get_bloginfo( 'version' ), $plugin['args']['minimum_wp_version'], '<' ) ) { + + $this->incompatible_wp_version_plugins[] = $plugin; + + // next plugin + continue; + } + + // add this plugin to the active list + if ( ! in_array( $plugin, $this->active_plugins ) ) { + $this->active_plugins[] = $plugin; + } + + // load the first found (highest versioned) payment gateway framework class, as needed + if ( isset( $plugin['args']['is_payment_gateway'] ) && ! class_exists( 'SV_WC_Payment_Gateway' ) ) { + require_once( $this->get_plugin_path( $plugin['path'] ) . '/lib/skyverge/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php' ); + } + + // initialize the plugin + $plugin['callback'](); + } + + // render update notices + if ( ( $this->incompatible_framework_plugins || $this->incompatible_wc_version_plugins || $this->incompatible_wp_version_plugins ) && is_admin() && ! defined( 'DOING_AJAX' ) && ! has_action( 'admin_notices', array( $this, 'render_update_notices' ) ) ) { + + add_action( 'admin_notices', array( $this, 'render_update_notices' ) ); + } + + /** + * WC Plugin Framework Plugins Loaded Action. + * + * Fired when all frameworked plugins are loaded. Frameworked plugins can + * hook into this action rather than `plugins_loaded`/`woocommerce_loaded` + * as needed. + * + * @since 2.0.0 + */ + do_action( 'sv_wc_framework_plugins_loaded' ); + } + + + /** Admin methods ******************************************************/ + + + /** + * Deactivate backwards-incompatible framework plugins, which will allow + * plugins with an older version of the framework to be active. Useful when + * the admin isn't ready to upgrade older plugins yet needs them to still + * function (e.g. a payment gateway) + * + * @since 4.0.0 + */ + public function maybe_deactivate_framework_plugins() { + + if ( isset( $_GET['sv_wc_framework_deactivate_newer'] ) ) { + if ( 'yes' == $_GET['sv_wc_framework_deactivate_newer'] ) { + + // don't want to just deactivate all active plugins willy-nilly if there's no incompatible plugins + if ( count( $this->incompatible_framework_plugins ) == 0 ) { + return; + } + + $plugins = array(); + + foreach ( $this->active_plugins as $plugin ) { + $plugins[] = plugin_basename( $plugin['path'] ); + } + + // deactivate all "active" frameworked plugins, these will be the newest, backwards-incompatible ones + deactivate_plugins( $plugins ); + + // redirect to the inactive plugin admin page, with a message indicating the number of plugins deactivated + wp_redirect( admin_url( 'plugins.php?plugin_status=inactive&sv_wc_framework_deactivate_newer=' . count( $plugins ) ) ); + exit; + } else { + // we're on the inactive plugin page and we've deactivated one or more plugins + add_action( 'admin_notices', array( $this, 'render_deactivation_notice' ) ); + } + } + } + + + /** + * Render a notice with a count of the backwards incompatible frameworked + * plugins that were deactivated + * + * @since 4.0.0 + */ + public function render_deactivation_notice() { + echo '

    '; + echo $_GET['sv_wc_framework_deactivate_newer'] > 1 ? + sprintf( 'Deactivated %d plugins', $_GET['sv_wc_framework_deactivate_newer'] ) : + 'Deactivated one plugin'; + echo '

    '; + } + + + /** + * Render a notice to update any plugins with incompatible framework + * versions, or incompatiblities with the current WooCommerce or WordPress + * versions + * + * @since 2.0.0 + */ + public function render_update_notices() { + + // must update plugin notice + if ( ! empty( $this->incompatible_framework_plugins ) ) { + + $plugin_count = count( $this->incompatible_framework_plugins ); + + echo '
    '; + + // describe the problem + echo '

    '; + echo esc_html( _n( 'The following plugin is disabled because it is out of date and incompatible with newer plugins on your site:', 'The following plugins are disabled because they are out of date and incompatible with newer plugins on your site:', $plugin_count, 'woocommerce-plugin-framework' ) ); + echo '

    '; + + // add a incompatible plugin list + echo '
      '; + foreach ( $this->incompatible_framework_plugins as $plugin ) { + printf( '
    • %s
    • ', esc_html( $plugin['plugin_name'] ) ); + } + echo '
    '; + + // describe the way to fix it + echo '

    '; + printf( + /** translators: Placeholders: %1$s - tag, %2$s - tag, %3$s - tag, %4$s - tag, %5$s - tag, %6$s - tag, %7$s - tag, %8$s - tag */ + esc_html( _n( 'To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s %5$sdeactivate%6$s the above plugin, or %7$sdeactivate the following%8$s:', 'To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s %5$sdeactivate%6$s the above plugins, or %7$sdeactivate the following%8$s:', $plugin_count, 'woocommerce-plugin-framework' ) ), + '', '', + '', '', + '', '', + '', '' + ); + echo '

    '; + + // add the list of active plugins + echo '
      '; + foreach ( $this->active_plugins as $plugin ) { + printf( '
    • %s
    • ', esc_html( $plugin['plugin_name'] ) ); + } + echo '
    '; + + echo '
    '; + } + + // must update WC notice + if ( ! empty( $this->incompatible_wc_version_plugins ) ) { + + printf( '

    %s

      ', count( $this->incompatible_wc_version_plugins ) > 1 ? esc_html__( 'The following plugins are inactive because they require a newer version of WooCommerce:', 'woocommerce-plugin-framework' ) : esc_html__( 'The following plugin is inactive because it requires a newer version of WooCommerce:', 'woocommerce-plugin-framework' ) ); + + foreach ( $this->incompatible_wc_version_plugins as $plugin ) { + + /* translators: Placeholders: %1$s - plugin name, %2$s - WooCommerce version number */ + echo '
    • ' . sprintf( esc_html__( '%1$s requires WooCommerce %2$s or newer', 'woocommerce-plugin-framework' ), esc_html( $plugin['plugin_name'] ), esc_html( $plugin['args']['minimum_wc_version'] ) ) . '
    • '; + } + + /* translators: Placeholders: %1$s - tag, %2$s - tag */ + echo '

    ' . sprintf( esc_html__( 'Please %1$supdate WooCommerce%2$s', 'woocommerce-plugin-framework' ), '', ' »' ) . '

    '; + } + + // must update WP notice + if ( ! empty( $this->incompatible_wp_version_plugins ) ) { + + printf( '

    %s

      ', count( $this->incompatible_wp_version_plugins ) > 1 ? 'The following plugins are inactive because they require a newer version of WordPress:' : 'The following plugin is inactive because it requires a newer version of WordPress:' ); + + foreach ( $this->incompatible_wp_version_plugins as $plugin ) { + printf( '
    • %s requires WordPress %s or newer
    • ', esc_html( $plugin['plugin_name'] ), esc_html( $plugin['args']['minimum_wp_version'] ) ); + } + + echo '

    Please update WordPress »

    '; + } + } + + + /** Helper methods ******************************************************/ + + + /** + * Is the WooCommerce plugin installed and active? This method is handy for + * frameworked plugins that are listed on wordpress.org and thus don't have + * access to the Woo Helper functions bundled with WooThemes-listed plugins. + * + * Notice: For now you can't rely on this method being available, since the + * bootstrap class is the only piece of the framework which is loaded + * simply according to the lexical order of plugin directories. Therefore + * to use, you should first check that this method exists, or if you really + * need to check for WooCommerce being active, define your own method. + * + * @since 4.0.0 + * @return boolean true if the WooCommerce plugin is installed and active + */ + public static function is_woocommerce_active() { + + $active_plugins = (array) get_option( 'active_plugins', array() ); + + if ( is_multisite() ) { + $active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) ); + } + + return in_array( 'woocommerce/woocommerce.php', $active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', $active_plugins ); + } + + + /** + * Compare the two framework versions. Returns -1 if $a is less than $b, 0 if + * they're equal, and 1 if $a is greater than $b + * + * @since 2.0.0 + * @param array $a first registered plugin to compare + * @param array $b second registered plugin to compare + * @return int -1 if $a is less than $b, 0 if they're equal, and 1 if $a is greater than $b + */ + public function compare_frameworks( $a, $b ) { + // compare versions without the operator argument, so we get a -1, 0 or 1 result + return version_compare( $b['version'], $a['version'] ); + } + + + /** + * Returns the plugin path for the given $file + * + * @since 2.0.0 + * @param string $file the file + * @return string plugin path + */ + public function get_plugin_path( $file ) { + return untrailingslashit( plugin_dir_path( $file ) ); + } + + + /** + * Returns the WooCommerce version number, backwards compatible to + * WC 1.5 + * + * @since 3.0.0 + * @return null|string + */ + protected function get_wc_version() { + + if ( defined( 'WC_VERSION' ) && WC_VERSION ) return WC_VERSION; + if ( defined( 'WOOCOMMERCE_VERSION' ) && WOOCOMMERCE_VERSION ) return WOOCOMMERCE_VERSION; + + return null; + } + +} + + +// instantiate the class +SV_WC_Framework_Bootstrap::instance(); + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-helper.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-helper.php new file mode 100644 index 0000000..98b9f7f --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-helper.php @@ -0,0 +1,1104 @@ + 'foo', 'item_2' => 'bar' ) + * + * array_insert_after( $array, 'item_1', array( 'item_1.5' => 'w00t' ) ) + * + * becomes + * + * array( 'item_1' => 'foo', 'item_1.5' => 'w00t', 'item_2' => 'bar' ) + * + * @since 2.2.0 + * @param array $array array to insert the given element into + * @param string $insert_key key to insert given element after + * @param array $element element to insert into array + * @return array + */ + public static function array_insert_after( Array $array, $insert_key, Array $element ) { + + $new_array = array(); + + foreach ( $array as $key => $value ) { + + $new_array[ $key ] = $value; + + if ( $insert_key == $key ) { + + foreach ( $element as $k => $v ) { + $new_array[ $k ] = $v; + } + } + } + + return $new_array; + } + + + /** + * Convert array into XML by recursively generating child elements + * + * First instantiate a new XML writer object: + * + * $xml = new XMLWriter(); + * + * Open in memory (alternatively you can use a local URI for file output) + * + * $xml->openMemory(); + * + * Then start the document + * + * $xml->startDocument( '1.0', 'UTF-8' ); + * + * Don't forget to end the document and output the memory + * + * $xml->endDocument(); + * + * $your_xml_string = $xml->outputMemory(); + * + * @since 2.2.0 + * + * @param \XMLWriter $xml_writer XML writer instance + * @param string|array $element_key name for element, e.g. + * @param string|array $element_value value for element, e.g. 100 + */ + public static function array_to_xml( $xml_writer, $element_key, $element_value = array() ) { + + if ( is_array( $element_value ) ) { + + // handle attributes + if ( '@attributes' === $element_key ) { + + foreach ( $element_value as $attribute_key => $attribute_value ) { + + $xml_writer->startAttribute( $attribute_key ); + $xml_writer->text( $attribute_value ); + $xml_writer->endAttribute(); + } + + return; + } + + // handle multi-elements (e.g. multiple elements) + if ( is_numeric( key( $element_value ) ) ) { + + // recursively generate child elements + foreach ( $element_value as $child_element_key => $child_element_value ) { + + $xml_writer->startElement( $element_key ); + + foreach ( $child_element_value as $sibling_element_key => $sibling_element_value ) { + self::array_to_xml( $xml_writer, $sibling_element_key, $sibling_element_value ); + } + + $xml_writer->endElement(); + } + + } else { + + // start root element + $xml_writer->startElement( $element_key ); + + // recursively generate child elements + foreach ( $element_value as $child_element_key => $child_element_value ) { + self::array_to_xml( $xml_writer, $child_element_key, $child_element_value ); + } + + // end root element + $xml_writer->endElement(); + } + + } else { + + // handle single elements + if ( '@value' === $element_key ) { + + $xml_writer->text( $element_value ); + + } else { + + // wrap element in CDATA tags if it contains illegal characters + if ( false !== strpos( $element_value, '<' ) || false !== strpos( $element_value, '>' ) ) { + + $xml_writer->startElement( $element_key ); + $xml_writer->writeCdata( $element_value ); + $xml_writer->endElement(); + + } else { + + $xml_writer->writeElement( $element_key, $element_value ); + } + } + } + } + + + /** + * Lists an array as text. + * + * Takes an array and returns a list like "one, two, three, and four" + * with a (mandatory) oxford comma. + * + * @since 5.2.0 + * + * @param array $items items to list + * @param string|null $conjunction coordinating conjunction, like "or" or "and" + * @param string $separator list separator, like a comma + * @return string + */ + public static function list_array_items( array $items, $conjunction = null, $separator = '' ) { + + if ( ! is_string( $conjunction ) ) { + $conjunction = _x( 'and', 'coordinating conjunction for a list of items: a, b, and c', 'woocommerce-plugin-framework' ); + } + + // append the conjunction to the last item + if ( count( $items ) > 1 ) { + + $last_item = array_pop( $items ); + + array_push( $items, trim( "{$conjunction} {$last_item}" ) ); + + // only use a comma if needed and no separator was passed + if ( count( $items ) < 3 ) { + $separator = ' '; + } elseif ( ! is_string( $separator ) || '' === $separator ) { + $separator = ', '; + } + } + + return implode( $separator, $items ); + } + + + /** Number helper functions *******************************************/ + + + /** + * Format a number with 2 decimal points, using a period for the decimal + * separator and no thousands separator. + * + * Commonly used for payment gateways which require amounts in this format. + * + * @since 3.0.0 + * @param float $number + * @return string + */ + public static function number_format( $number ) { + + return number_format( (float) $number, 2, '.', '' ); + } + + + /** WooCommerce helper functions **************************************/ + + + /** + * Gets order line items (products) as an array of objects. + * + * Object properties: + * + * + id - item ID + * + name - item name, usually product title, processed through htmlentities() + * + description - formatted item meta (e.g. Size: Medium, Color: blue), processed through htmlentities() + * + quantity - item quantity + * + item_total - item total (line total divided by quantity, excluding tax & rounded) + * + line_total - line item total (excluding tax & rounded) + * + meta - formatted item meta array + * + product - item product or null if getting product from item failed + * + item - raw item array + * + * @since 3.0.0 + * + * @param \WC_Order $order + * @return \stdClass[] array of line item objects + */ + public static function get_order_line_items( $order ) { + + $line_items = []; + + /** @var \WC_Order_Item_Product $item */ + foreach ( $order->get_items() as $id => $item ) { + + $line_item = new \stdClass(); + $product = $item->get_product(); + $name = $item->get_name(); + $quantity = $item->get_quantity(); + $sku = $product instanceof \WC_Product ? $product->get_sku() : ''; + $item_desc = []; + + // add SKU to description if available + if ( ! empty( $sku ) ) { + $item_desc[] = sprintf( 'SKU: %s', $sku ); + } + + $meta_data = $item->get_formatted_meta_data( '-', true ); + $item_meta = []; + + foreach ( $meta_data as $meta ) { + $item_meta[] = array( + 'label' => $meta->display_key, + 'value' => $meta->value, + ); + } + + if ( ! empty( $item_meta ) ) { + foreach ( $item_meta as $meta ) { + $item_desc[] = sprintf( '%s: %s', $meta['label'], $meta['value'] ); + } + } + + $item_desc = implode( ', ', $item_desc ); + + $line_item->id = $id; + $line_item->name = htmlentities( $name, ENT_QUOTES, 'UTF-8', false ); + $line_item->description = htmlentities( $item_desc, ENT_QUOTES, 'UTF-8', false ); + $line_item->quantity = $quantity; + $line_item->item_total = isset( $item['recurring_line_total'] ) ? $item['recurring_line_total'] : $order->get_item_total( $item ); + $line_item->line_total = $order->get_line_total( $item ); + $line_item->meta = $item_meta; + $line_item->product = is_object( $product ) ? $product : null; + $line_item->item = $item; + + $line_items[] = $line_item; + } + + return $line_items; + } + + + /** + * Determines if an order contains only virtual products. + * + * @since 4.5.0 + * + * @param \WC_Order $order the order object + * @return bool + */ + public static function is_order_virtual( \WC_Order $order ) { + + $is_virtual = true; + + /** @var \WC_Order_Item_Product $item */ + foreach ( $order->get_items() as $item ) { + + $product = $item->get_product(); + + // once we've found one non-virtual product we know we're done, break out of the loop + if ( $product && ! $product->is_virtual() ) { + + $is_virtual = false; + break; + } + } + + return $is_virtual; + } + + + /** + * Determines if a shop has any published virtual products. + * + * @since 5.10.0 + * + * @return bool + */ + public static function shop_has_virtual_products() { + + $virtual_products = wc_get_products( [ + 'virtual' => true, + 'status' => 'publish', + 'limit' => 1, + ] ); + + return sizeof( $virtual_products ) > 0; + } + + + /** + * Safely gets a value from $_POST. + * + * If the expected data is a string also trims it. + * + * @since 5.5.0 + * + * @param string $key posted data key + * @param int|float|array|bool|null|string $default default data type to return (default empty string) + * @return int|float|array|bool|null|string posted data value if key found, or default + */ + public static function get_posted_value( $key, $default = '' ) { + + $value = $default; + + if ( isset( $_POST[ $key ] ) ) { + $value = is_string( $_POST[ $key ] ) ? trim( $_POST[ $key ] ) : $_POST[ $key ]; + } + + return $value; + } + + + /** + * Safely gets a value from $_REQUEST. + * + * If the expected data is a string also trims it. + * + * @since 5.5.0 + * + * @param string $key posted data key + * @param int|float|array|bool|null|string $default default data type to return (default empty string) + * @return int|float|array|bool|null|string posted data value if key found, or default + */ + public static function get_requested_value( $key, $default = '' ) { + + $value = $default; + + if ( isset( $_REQUEST[ $key ] ) ) { + $value = is_string( $_REQUEST[ $key ] ) ? trim( $_REQUEST[ $key ] ) : $_REQUEST[ $key ]; + } + + return $value; + } + + + /** + * Get the count of notices added, either for all notices (default) or for one + * particular notice type specified by $notice_type. + * + * WC notice functions are not available in the admin + * + * @since 3.0.2 + * @param string $notice_type The name of the notice type - either error, success or notice. [optional] + * @return int + */ + public static function wc_notice_count( $notice_type = '' ) { + + if ( function_exists( 'wc_notice_count' ) ) { + return wc_notice_count( $notice_type ); + } + + return 0; + } + + + /** + * Add and store a notice. + * + * WC notice functions are not available in the admin + * + * @since 3.0.2 + * @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] + */ + public static function wc_add_notice( $message, $notice_type = 'success' ) { + + if ( function_exists( 'wc_add_notice' ) ) { + wc_add_notice( $message, $notice_type ); + } + } + + + /** + * Print a single notice immediately + * + * WC notice functions are not available in the admin + * + * @since 3.0.2 + * @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] + */ + public static function wc_print_notice( $message, $notice_type = 'success' ) { + + if ( function_exists( 'wc_print_notice' ) ) { + wc_print_notice( $message, $notice_type ); + } + } + + + /** + * Gets the full URL to the log file for a given $handle + * + * @since 4.0.0 + * @param string $handle log handle + * @return string URL to the WC log file identified by $handle + */ + public static function get_wc_log_file_url( $handle ) { + return admin_url( sprintf( 'admin.php?page=wc-status&tab=logs&log_file=%s-%s-log', $handle, sanitize_file_name( wp_hash( $handle ) ) ) ); + } + + + /** + * Gets the current WordPress site name. + * + * This is helpful for retrieving the actual site name instead of the + * network name on multisite installations. + * + * @since 4.6.0 + * @return string + */ + public static function get_site_name() { + + return ( is_multisite() ) ? get_blog_details()->blogname : get_bloginfo( 'name' ); + } + + + /** JavaScript helper functions ***************************************/ + + + /** + * Enhanced search JavaScript (Select2) + * + * Enqueues JavaScript required for AJAX search with Select2. + * + * @codeCoverageIgnore no need to unit test this since it's mostly JavaScript + * + * @since 3.1.0 + */ + public static function render_select2_ajax() { + + if ( ! did_action( 'sv_wc_select2_ajax_rendered' ) ) { + + $javascript = "( function(){ + if ( ! $().select2 ) return; + "; + + // Ensure localized strings are used. + $javascript .= " + + function getEnhancedSelectFormatString() { + + if ( 'undefined' !== typeof wc_select_params ) { + wc_enhanced_select_params = wc_select_params; + } + + if ( 'undefined' === typeof wc_enhanced_select_params ) { + return {}; + } + + var formatString = { + formatMatches: function( matches ) { + if ( 1 === matches ) { + return wc_enhanced_select_params.i18n_matches_1; + } + + return wc_enhanced_select_params.i18n_matches_n.replace( '%qty%', matches ); + }, + formatNoMatches: function() { + return wc_enhanced_select_params.i18n_no_matches; + }, + formatAjaxError: function( jqXHR, textStatus, errorThrown ) { + return wc_enhanced_select_params.i18n_ajax_error; + }, + formatInputTooShort: function( input, min ) { + var number = min - input.length; + + if ( 1 === number ) { + return wc_enhanced_select_params.i18n_input_too_short_1 + } + + return wc_enhanced_select_params.i18n_input_too_short_n.replace( '%qty%', number ); + }, + formatInputTooLong: function( input, max ) { + var number = input.length - max; + + if ( 1 === number ) { + return wc_enhanced_select_params.i18n_input_too_long_1 + } + + return wc_enhanced_select_params.i18n_input_too_long_n.replace( '%qty%', number ); + }, + formatSelectionTooBig: function( limit ) { + if ( 1 === limit ) { + return wc_enhanced_select_params.i18n_selection_too_long_1; + } + + return wc_enhanced_select_params.i18n_selection_too_long_n.replace( '%qty%', number ); + }, + formatLoadMore: function( pageNumber ) { + return wc_enhanced_select_params.i18n_load_more; + }, + formatSearching: function() { + return wc_enhanced_select_params.i18n_searching; + } + }; + + return formatString; + } + "; + + $javascript .= " + + $( 'select.sv-wc-enhanced-search' ).filter( ':not(.enhanced)' ).each( function() { + + var select2_args = { + allowClear: $( this ).data( 'allow_clear' ) ? true : false, + placeholder: $( this ).data( 'placeholder' ), + minimumInputLength: $( this ).data( 'minimum_input_length' ) ? $( this ).data( 'minimum_input_length' ) : '3', + escapeMarkup: function( m ) { + return m; + }, + ajax: { + url: '" . esc_js( admin_url( 'admin-ajax.php' ) ) . "', + dataType: 'json', + cache: true, + delay: 250, + data: function( params ) { + return { + term: params.term, + request_data: $( this ).data( 'request_data' ) ? $( this ).data( 'request_data' ) : {}, + action: $( this ).data( 'action' ) || 'woocommerce_json_search_products_and_variations', + security: $( this ).data( 'nonce' ) + }; + }, + processResults: function( data, params ) { + var terms = []; + if ( data ) { + $.each( data, function( id, text ) { + terms.push( { id: id, text: text } ); + }); + } + return { results: terms }; + } + } + }; + + select2_args = $.extend( select2_args, getEnhancedSelectFormatString() ); + + $( this ).select2( select2_args ).addClass( 'enhanced' ); + } ); + "; + + $javascript .= '} )();'; + + wc_enqueue_js( $javascript ); + + /** + * WC Select2 Ajax Rendered Action. + * + * Fired when an Ajax select2 is rendered. + * + * @since 3.1.0 + */ + do_action( 'sv_wc_select2_ajax_rendered' ); + } + } + + + /** Framework translation functions ***********************************/ + + + /** + * Gettext `__()` wrapper for framework-translated strings + * + * Warning! This function should only be used if an existing + * translation from the framework is to be used. It should + * never be called for plugin-specific or untranslated strings! + * Untranslated = not registered via string literal. + * + * @since 4.1.0 + * @param string $text + * @return string translated text + */ + public static function f__( $text ) { + + return __( $text, 'woocommerce-plugin-framework' ); + } + + + /** + * Gettext `_e()` wrapper for framework-translated strings + * + * Warning! This function should only be used if an existing + * translation from the framework is to be used. It should + * never be called for plugin-specific or untranslated strings! + * Untranslated = not registered via string literal. + * + * @since 4.1.0 + * @param string $text + */ + public static function f_e( $text ) { + + _e( $text, 'woocommerce-plugin-framework' ); + } + + + /** + * Gettext `_x()` wrapper for framework-translated strings + * + * Warning! This function should only be used if an existing + * translation from the framework is to be used. It should + * never be called for plugin-specific or untranslated strings! + * Untranslated = not registered via string literal. + * + * @since 4.1.0 + * + * @param string $text + * @param string $context + * @return string translated text + */ + public static function f_x( $text, $context ) { + + return _x( $text, $context, 'woocommerce-plugin-framework' ); + } + + + /** Misc functions ****************************************************/ + + + /** + * Gets the WordPress current screen. + * + * @see get_current_screen() replacement which is always available, unlike the WordPress core function + * + * @since 5.4.2 + * + * @return \WP_Screen|null + */ + public static function get_current_screen() { + global $current_screen; + + return $current_screen ?: null; + } + + + /** + * Checks if the current screen matches a specified ID. + * + * This helps avoiding using the get_current_screen() function which is not always available, + * or setting the substitute global $current_screen every time a check needs to be performed. + * + * @since 5.4.2 + * + * @param string $id id (or property) to compare + * @param string $prop optional property to compare, defaults to screen id + * @return bool + */ + public static function is_current_screen( $id, $prop = 'id' ) { + global $current_screen; + + return isset( $current_screen->$prop ) && $id === $current_screen->$prop; + } + + + /** + * Determines if viewing an enhanced admin screen. + * + * @since 5.6.0 + * + * @return bool + */ + public static function is_enhanced_admin_screen() { + + return is_admin() && SV_WC_Plugin_Compatibility::is_enhanced_admin_available() && ( \Automattic\WooCommerce\Admin\Loader::is_admin_page() || \Automattic\WooCommerce\Admin\Loader::is_embed_page() ); + } + + + /** + * Determines whether the new WooCommerce enhanced navigation is supported and enabled. + * + * @since 5.10.6 + * + * @return bool + */ + public static function is_wc_navigation_enabled() { + + return + is_callable( [ \Automattic\WooCommerce\Admin\Features\Navigation\Screen::class, 'register_post_type' ] ) && + is_callable( [ \Automattic\WooCommerce\Admin\Features\Navigation\Menu::class, 'add_plugin_item' ] ) && + is_callable( [ \Automattic\WooCommerce\Admin\Features\Navigation\Menu::class, 'add_plugin_category' ] ) && + is_callable( [ \Automattic\WooCommerce\Admin\Features\Features::class, 'is_enabled' ] ) && + \Automattic\WooCommerce\Admin\Features\Features::is_enabled( 'navigation' ); + } + + + /** + * Determines if the current request is for a WC REST API endpoint. + * + * @see \WooCommerce::is_rest_api_request() + * + * @since 5.9.0 + * + * @return bool + */ + public static function is_rest_api_request() { + + if ( is_callable( 'WC' ) && is_callable( [ WC(), 'is_rest_api_request' ] ) ) { + return (bool) WC()->is_rest_api_request(); + } + + if ( empty( $_SERVER['REQUEST_URI'] ) || ! function_exists( 'rest_get_url_prefix' ) ) { + return false; + } + + $rest_prefix = trailingslashit( rest_get_url_prefix() ); + $is_rest_api_request = false !== strpos( $_SERVER['REQUEST_URI'], $rest_prefix ); + + /* applies WooCommerce core filter */ + return (bool) apply_filters( 'woocommerce_is_rest_api_request', $is_rest_api_request ); + } + + + /** + * Displays a notice if the provided hook has not yet run. + * + * @since 5.2.0 + * + * @param string $hook action hook to check + * @param string $method method/function name + * @param string $version version the notice was added + */ + public static function maybe_doing_it_early( $hook, $method, $version ) { + + if ( ! did_action( $hook ) ) { + wc_doing_it_wrong( $method, "This should only be called after '{$hook}'", $version ); + } + } + + + /** + * Triggers a PHP error. + * + * This wrapper method ensures AJAX isn't broken in the process. + * + * @since 4.6.0 + * @param string $message the error message + * @param int $type Optional. The error type. Defaults to E_USER_NOTICE + */ + public static function trigger_error( $message, $type = E_USER_NOTICE ) { + + if ( is_callable( 'wp_doing_ajax' ) && wp_doing_ajax() ) { + + switch ( $type ) { + + case E_USER_NOTICE: + $prefix = 'Notice: '; + break; + + case E_USER_WARNING: + $prefix = 'Warning: '; + break; + + default: + $prefix = ''; + } + + error_log( $prefix . $message ); + + } else { + + trigger_error( $message, $type ); + } + } + + + /** + * Converts an array of strings to a comma separated list of strings, escaped for SQL use. + * + * This can be safely used in SQL IN clauses. + * + * @since 5.10.9 + * + * @param string[] $values + * @return string + */ + public static function get_escaped_string_list( array $values ) { + global $wpdb; + + return (string) $wpdb->prepare( implode( ', ', array_fill( 0, count( $values ), '%s' ) ), $values ); + } + + + /** + * Converts an array of numerical integers into a comma separated list of IDs. + * + * This can be safely used for SQL IN clauses. + * + * @since 5.10.9 + * + * @param int[] $ids + * @return string + */ + public static function get_escaped_id_list( array $ids ) { + + return implode( ',', array_unique( array_map( 'intval', $ids ) ) ); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-hook-deprecator.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-hook-deprecator.php new file mode 100644 index 0000000..f2d7262 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-hook-deprecator.php @@ -0,0 +1,199 @@ +plugin_name = $plugin_name; + $this->hooks = array_map( array( $this, 'set_hook_defaults' ), $hooks ); + + $this->map_deprecated_hooks(); + + add_action( 'shutdown', array( $this, 'trigger_deprecated_errors' ), 999 ); + } + + + /** + * Sets the deprecated hook defaults. + * + * @since 4.5.0 + * @param array $hook_params the hook parameters + * @return array + */ + protected function set_hook_defaults( $hook_params ) { + + $defaults = array( + 'removed' => false, + 'map' => false, + 'replacement' => '', + ); + + return wp_parse_args( $hook_params, $defaults ); + } + + + /** + * Map each deprecated hook to its replacement. + * + * @since 4.5.0 + */ + protected function map_deprecated_hooks() { + + foreach ( $this->hooks as $old_hook => $hook ) { + + if ( ! empty( $hook['replacement'] ) && $hook['removed'] && $hook['map'] ) { + add_filter( $hook['replacement'], array( $this, 'map_deprecated_hook' ), 10, 10 ); + } + } + } + + + /** + * Map a deprecated/renamed hook to a new one. + * + * This method works by hooking into the new, renamed version of the action/filter + * and checking if any actions/filters are hooked into the old hook. It then runs + * these and applies the data modifications in the new hook. + * + * @since 4.5.0 + * @return mixed + */ + public function map_deprecated_hook() { + + $args = func_get_args(); + $data = $args[0]; + $new_hook = current_filter(); + + $new_hooks = wp_list_pluck( $this->hooks, 'replacement' ); + + // check if there are matching old hooks for the current hook + foreach ( array_keys( $new_hooks, $new_hook ) as $old_hook ) { + + // check if there are any hooks added to the old hook + if ( has_filter( $old_hook ) ) { + + // prepend old hook name to the args + array_unshift( $args, $old_hook ); + + // apply the hooks attached to the old hook to $data + $data = call_user_func_array( 'apply_filters', $args ); + } + } + + return $data; + } + + + /** + * Trigger a notice when other actors have attached callbacks to hooks that + * are either deprecated or removed. This only runs when WP_DEBUG is on. + * + * @since 4.3.0 + */ + public function trigger_deprecated_errors() { + global $wp_filter; + + // follow WP core behavior for showing deprecated notices and only do so when WP_DEBUG is on + if ( defined( 'WP_DEBUG' ) && WP_DEBUG && apply_filters( 'sv_wc_plugin_framework_show_deprecated_hook_notices', true ) ) { + + // sanity check + if ( ! is_array( $wp_filter ) || empty( $wp_filter ) ) { + return; + } + + foreach ( $this->hooks as $old_hook_tag => $hook ) { + + // if other actors have attached a callback to the deprecated/removed hook... + if ( isset( $wp_filter[ $old_hook_tag ] ) ) { + + $this->trigger_error( $old_hook_tag, $hook ); + } + } + } + } + + + /** + * Trigger the deprecated/removed notice + * + * @since 4.3.0 + * @param string $old_hook_name deprecated/removed hook name + * @param array $hook { + * @type string $version version the hook was deprecated/removed in + * @type bool $removed if present and true, the message will indicate the hook was removed instead of deprecated + * @type string|bool $replacement if present and a string, the message will indicate the replacement hook to use, + * otherwise (if bool and false) the message will indicate there is no replacement available. + * } + */ + protected function trigger_error( $old_hook_name, $hook ) { + + // e.g. WooCommerce Memberships: "wc_memberships_some_hook" was deprecated in version 1.2.3. + $message = sprintf( '%1$s: action/filter "%2$s" was %3$s in version %4$s. ', + $this->plugin_name, + $old_hook_name, + $hook['removed'] ? 'removed' : 'deprecated', + $hook['version'] + ); + + // e.g. Use "wc_memberships_some_new_hook" instead. + $message .= ! empty( $hook['replacement'] ) ? sprintf( 'Use %1$s instead.', $hook['replacement'] ) : 'There is no replacement available.'; + + // triggers as E_USER_NOTICE + SV_WC_Helper::trigger_error( $message ); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-compatibility.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-compatibility.php new file mode 100644 index 0000000..ff752b9 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-compatibility.php @@ -0,0 +1,367 @@ + 1 ] ); + + if ( is_array( $wp_org_request ) && isset( $wp_org_request['body'] ) ) { + + $plugin_info = json_decode( $wp_org_request['body'], true ); + + if ( is_array( $plugin_info ) && ! empty( $plugin_info['versions'] ) && is_array( $plugin_info['versions'] ) ) { + + $latest_wc_versions = []; + + // reverse array as WordPress supplies oldest version first, newest last + foreach ( array_keys( array_reverse( $plugin_info['versions'] ) ) as $wc_version ) { + + // skip trunk, release candidates, betas and other non-final or irregular versions + if ( + is_string( $wc_version ) + && '' !== $wc_version + && is_numeric( $wc_version[0] ) + && false === strpos( $wc_version, '-' ) + ) { + $latest_wc_versions[] = $wc_version; + } + } + + set_transient( 'sv_wc_plugin_wc_versions', $latest_wc_versions, WEEK_IN_SECONDS ); + } + } + } + + return is_array( $latest_wc_versions ) ? $latest_wc_versions : []; + } + + + /** + * Gets the version of the currently installed WooCommerce. + * + * @since 3.0.0 + * + * @return string|null Woocommerce version number or null if undetermined + */ + public static function get_wc_version() { + + return defined( 'WC_VERSION' ) && WC_VERSION ? WC_VERSION : null; + } + + + /** + * Determines if the installed WooCommerce version matches a specific version. + * + * @since 5.5.0 + * + * @param string $version semver + * @return bool + */ + public static function is_wc_version( $version ) { + + $wc_version = self::get_wc_version(); + + // accounts for semver cases like 3.0 being equal to 3.0.0 + return $wc_version === $version || ( $wc_version && version_compare( $wc_version, $version, '=' ) ); + } + + + /** + * Determines if the installed version of WooCommerce is equal or greater than a given version. + * + * @since 4.7.3 + * + * @param string $version version number to compare + * @return bool + */ + public static function is_wc_version_gte( $version ) { + + $wc_version = self::get_wc_version(); + + return $wc_version && version_compare( $wc_version, $version, '>=' ); + } + + + /** + * Determines if the installed version of WooCommerce is lower than a given version. + * + * @since 4.7.3 + * + * @param string $version version number to compare + * @return bool + */ + public static function is_wc_version_lt( $version ) { + + $wc_version = self::get_wc_version(); + + return $wc_version && version_compare( $wc_version, $version, '<' ); + } + + + /** + * Determines if the installed version of WooCommerce is greater than a given version. + * + * @since 2.0.0 + * + * @param string $version the version to compare + * @return bool + */ + public static function is_wc_version_gt( $version ) { + + $wc_version = self::get_wc_version(); + + return $wc_version && version_compare( $wc_version, $version, '>' ); + } + + + /** + * Determines whether the enhanced admin is available. + * + * This checks both for WooCommerce v4.0+ and the underlying package availability. + * + * @since 5.6.0 + * + * @return bool + */ + public static function is_enhanced_admin_available() { + + return self::is_wc_version_gte( '4.0' ) && function_exists( 'wc_admin_url' ); + } + + + /** WordPress core ******************************************************/ + + + /** + * Normalizes a WooCommerce page screen ID. + * + * Needed because WordPress uses a menu title (which is translatable), not slug, to generate screen ID. + * See details in: https://core.trac.wordpress.org/ticket/21454 + * TODO: Add WP version check when https://core.trac.wordpress.org/ticket/18857 is addressed {BR 2016-12-12} + * + * @since 4.6.0 + * + * @param string $slug slug for the screen ID to normalize (minus `woocommerce_page_`) + * @return string normalized screen ID + */ + public static function normalize_wc_screen_id( $slug = 'wc-settings' ) { + + // The textdomain usage is intentional here, we need to match the menu title. + $prefix = sanitize_title( __( 'WooCommerce', 'woocommerce' ) ); + + return $prefix . '_page_' . $slug; + } + + + /** + * Converts a shorthand byte value to an integer byte value. + * + * Wrapper for wp_convert_hr_to_bytes(), moved to load.php in WordPress 4.6 from media.php + * + * Based on ActionScheduler's compat wrapper for the same function: + * ActionScheduler_Compatibility::convert_hr_to_bytes() + * + * @link https://secure.php.net/manual/en/function.ini-get.php + * @link https://secure.php.net/manual/en/faq.using.php#faq.using.shorthandbytes + * + * @since 5.3.1 + * + * @param string $value A (PHP ini) byte value, either shorthand or ordinary. + * @return int An integer byte value. + */ + public static function convert_hr_to_bytes( $value ) { + + if ( function_exists( 'wp_convert_hr_to_bytes' ) ) { + + return wp_convert_hr_to_bytes( $value ); + } + + $value = strtolower( trim( $value ) ); + $bytes = (int) $value; + + if ( false !== strpos( $value, 'g' ) ) { + + $bytes *= GB_IN_BYTES; + + } elseif ( false !== strpos( $value, 'm' ) ) { + + $bytes *= MB_IN_BYTES; + + } elseif ( false !== strpos( $value, 'k' ) ) { + + $bytes *= KB_IN_BYTES; + } + + // deal with large (float) values which run into the maximum integer size + return min( $bytes, PHP_INT_MAX ); + } + + + /** Subscriptions *********************************************************/ + + + /** + * Determines if the installed version of WooCommerce Subscriptions matches or exceeds a given version. + * + * @since 5.5.0 + * + * @param string $version version number to compare + * @return bool + */ + public static function is_wc_subscriptions_version_gte( $version ) { + + $subscriptions_version = self::get_wc_subscriptions_version(); + + return $subscriptions_version && version_compare( $subscriptions_version, $version, '>=' ); + } + + /** + * Determines if the installed version of WooCommerce Subscriptions exceeds a given version. + * + * @since 5.5.0 + * + * @param string $version version number to compare + * @return bool + */ + public static function is_wc_subscriptions_version_gt( $version ) { + + $subscriptions_version = self::get_wc_subscriptions_version(); + + return $subscriptions_version && version_compare( $subscriptions_version, $version, '>' ); + } + + + /** + * Determines if the installed version of WooCommerce Subscriptions is lower than a given version. + * + * @since 5.5.0 + * + * @param string $version version number to compare + * @return bool + */ + public static function is_wc_subscriptions_version_lt( $version ) { + + $subscriptions_version = self::get_wc_subscriptions_version(); + + return $subscriptions_version && version_compare( $subscriptions_version, $version, '<' ); + } + + + /** + * Gets the version of the currently installed WooCommerce Subscriptions. + * + * @since 4.1.0 + * + * @return string|null WooCommerce Subscriptions version number or null if not found + */ + protected static function get_wc_subscriptions_version() { + + return class_exists( 'WC_Subscriptions' ) && ! empty( \WC_Subscriptions::$version ) ? \WC_Subscriptions::$version : null; + } + + + /** + * Determines if the installed WooCommerce Subscriptions version matches a specific version. + * + * @since 5.5.0 + * + * @param string $version semver + * @return bool + */ + protected static function is_wc_subscriptions_version( $version ) { + + $subscriptions_version = self::get_wc_subscriptions_version(); + + // accounts for semver cases like 2.2 being equal to 2.2.0 + return $version === $subscriptions_version || ( $subscriptions_version && version_compare( $version, $subscriptions_version, '=' ) ); + } + + + /** + * Determines whether HPOS is enabled. + * + * @link https://woocommerce.com/document/high-performance-order-storage/ + * @link https://github.com/woocommerce/woocommerce/wiki/High-Performance-Order-Storage-Upgrade-Recipe-Book#detecting-whether-hpos-tables-are-being-used-in-the-store + * + * @since 5.11.0 + * + * @return bool + */ + public static function is_hpos_enabled() : bool { + + return is_callable( OrderUtil::class . '::' . 'custom_orders_table_usage_is_enabled' ) + && OrderUtil::custom_orders_table_usage_is_enabled(); + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php new file mode 100644 index 0000000..8a6ea92 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php @@ -0,0 +1,523 @@ +plugin = $plugin; + + $dependencies = $this->parse_dependencies( $args ); + + $this->php_extensions = (array) $dependencies['php_extensions']; + $this->php_functions = (array) $dependencies['php_functions']; + $this->php_settings = (array) $dependencies['php_settings']; + + // add the action & filter hooks + $this->add_hooks(); + } + + + /** + * Parses the dependency arguments and sets defaults. + * + * @since 5.2.0 + * + * @param array $args dependency args + * @return array + */ + private function parse_dependencies( $args ) { + + $dependencies = wp_parse_args( $args, array( + 'php_extensions' => array(), + 'php_functions' => array(), + 'php_settings' => array(), + ) ); + + $default_settings = array( + 'suhosin.post.max_array_index_length' => 256, + 'suhosin.post.max_totalname_length' => 65535, + 'suhosin.post.max_vars' => 1024, + 'suhosin.request.max_array_index_length' => 256, + 'suhosin.request.max_totalname_length' => 65535, + 'suhosin.request.max_vars' => 1024, + ); + + // override any default settings requirements if the plugin specifies them + if ( ! empty( $dependencies['php_settings'] ) ) { + $dependencies['php_settings'] = array_merge( $default_settings, $dependencies['php_settings'] ); + } + + return $dependencies; + } + + + /** + * Adds the action & filter hooks. + * + * @since 5.2.0 + */ + protected function add_hooks() { + + // add the admin dependency notices + add_action( 'admin_init', array( $this, 'add_admin_notices' ) ); + } + + + /** + * Adds the admin dependency notices. + * + * @since 5.2.0 + */ + public function add_admin_notices() { + + $this->add_php_extension_notices(); + $this->add_php_function_notices(); + $this->add_php_settings_notices(); + + $this->add_deprecated_notices(); + } + + + /** + * Adds notices for any missing PHP extensions. + * + * @since 5.2.0 + */ + public function add_php_extension_notices() { + + $missing_extensions = $this->get_missing_php_extensions(); + + if ( count( $missing_extensions ) > 0 ) { + + $message = sprintf( + /* translators: Placeholders: %1$s - plugin name, %2$s - a PHP extension/comma-separated list of PHP extensions */ + _n( + '%1$s requires the %2$s PHP extension to function. Contact your host or server administrator to install and configure the missing extension.', + '%1$s requires the following PHP extensions to function: %2$s. Contact your host or server administrator to install and configure the missing extensions.', + count( $missing_extensions ), + 'woocommerce-plugin-framework' + ), + esc_html( $this->get_plugin()->get_plugin_name() ), + '' . implode( ', ', $missing_extensions ) . '' + ); + + $this->add_admin_notice( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-missing-extensions', $message, 'error' ); + } + } + + + /** + * Adds notices for any missing PHP functions. + * + * @since 5.2.0 + */ + public function add_php_function_notices() { + + $missing_functions = $this->get_missing_php_functions(); + + if ( count( $missing_functions ) > 0 ) { + + $message = sprintf( + /* translators: Placeholders: %1$s - plugin name, %2$s - a PHP function/comma-separated list of PHP functions */ + _n( + '%1$s requires the %2$s PHP function to exist. Contact your host or server administrator to install and configure the missing function.', + '%1$s requires the following PHP functions to exist: %2$s. Contact your host or server administrator to install and configure the missing functions.', + count( $missing_functions ), + 'woocommerce-plugin-framework' + ), + esc_html( $this->get_plugin()->get_plugin_name() ), + '' . implode( ', ', $missing_functions ) . '' + ); + + $this->add_admin_notice( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-missing-functions', $message, 'error' ); + } + } + + + /** + * Adds notices for any incompatible PHP settings. + * + * @since 5.2.0 + */ + public function add_php_settings_notices() { + + if ( isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] ) { + + $bad_settings = $this->get_incompatible_php_settings(); + + if ( count( $bad_settings ) > 0 ) { + + $message = sprintf( + /* translators: Placeholders: %s - plugin name */ + __( '%s may behave unexpectedly because the following PHP configuration settings are required:' ), + '' . esc_html( $this->get_plugin()->get_plugin_name() ) . '' + ); + + $message .= '
      '; + + foreach ( $bad_settings as $setting => $values ) { + + $setting_message = '' . $setting . ' = ' . $values['expected'] . ''; + + if ( ! empty( $values['type'] ) && 'min' === $values['type'] ) { + + $setting_message = sprintf( + /** translators: Placeholders: %s - a PHP setting value */ + __( '%s or higher', 'woocommerce-plugin-framework' ), + $setting_message + ); + } + + $message .= '
    • ' . $setting_message . '
    • '; + } + + $message .= '
    '; + + $message .= __( 'Please contact your hosting provider or server administrator to configure these settings.', 'woocommerce-plugin-framework' ); + + $this->add_admin_notice( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-incompatibile-php-settings', $message, 'warning' ); + } + } + } + + + /** + * Gets any deprecated warning notices. + * + * @since 5.2.0 + */ + protected function add_deprecated_notices() { + + // add a notice for PHP < 5.6 + if ( version_compare( PHP_VERSION, '5.6.0', '<' ) ) { + + $message = '

    '; + + $message .= sprintf( + /* translators: Placeholders: %1$s - , %2$s - */ + __( 'Hey there! We\'ve noticed that your server is running %1$san outdated version of PHP%2$s, which is the programming language that WooCommerce and its extensions are built on. + The PHP version that is currently used for your site is no longer maintained, nor %1$sreceives security updates%2$s; newer versions are faster and more secure. + As a result, %3$s no longer supports this version and you should upgrade PHP as soon as possible. + Your hosting provider can do this for you. %4$sHere are some resources to help you upgrade%5$s and to explain PHP versions further.', 'woocommerce-plugin-framework' ), + '', '', + esc_html( $this->get_plugin()->get_plugin_name() ), + '', '' + ); + + $message .= '

    '; + + $this->add_admin_notice( 'sv-wc-deprecated-php-version', $message, 'error' ); + } + } + + + /** + * Adds an admin notice. + * + * @since 5.2.0 + * + * @param string $id notice ID + * @param string $message notice message + * @param string $type notice type + */ + protected function add_admin_notice( $id, $message, $type = 'info' ) { + + $notice_class = $type; + + // translate the types into WP notice classes + switch ( $type ) { + + case 'error': + $notice_class = 'notice-error'; + break; + + case 'warning': + $notice_class = 'notice-warning'; + break; + + case 'info': + $notice_class = 'notice-info'; + break; + + case 'success': + $notice_class = 'notice-success'; + break; + } + + $this->get_plugin()->get_admin_notice_handler()->add_admin_notice( $message, $id, array( + 'notice_class' => $notice_class, + ) ); + } + + + /** + * Returns the active scripts optimization plugins. + * + * Returns a key-value array where the key contains the plugin file identifier and the value is the name of the plugin. + * + * @since 5.7.0 + * + * @return array + */ + public function get_active_scripts_optimization_plugins() { + + /** + * Filters script optimization plugins to look for. + * + * @since 5.7.0 + * + * @param array $plugins an array of file identifiers (keys) and plugin names (values) + */ + $plugins = (array) apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_scripts_optimization_plugins', [ + 'async-javascript.php' => 'Async JavaScript', + 'autoptimize.php' => 'Autoptimize', + 'wp-hummingbird.php' => 'Hummingbird', + 'sg-optimizer.php' => 'SG Optimizer', + 'w3-total-cache.php' => 'W3 Total Cache', + 'wpFastestCache.php' => 'WP Fastest Cache', + 'wp-rocket.php' => 'WP Rocket', + ] ); + + $active_plugins = []; + + foreach ( $plugins as $filename => $plugin_name ) { + + if ( $this->get_plugin()->is_plugin_active( $filename ) ) { + + $active_plugins[ $filename ] = $plugin_name; + } + } + + return $active_plugins; + } + + + /** + * Returns true if any of the known scripts optimization plugins is active. + * + * @since 5.7.0 + * + * @return bool + */ + public function is_scripts_optimization_plugin_active() { + + return ! empty( $this->get_active_scripts_optimization_plugins() ); + } + + + /** Getter methods ********************************************************/ + + + /** + * Gets any missing PHP extensions. + * + * @since 5.2.0 + * + * @return array + */ + public function get_missing_php_extensions() { + + $missing_extensions = []; + + foreach ( $this->get_php_extensions() as $extension ) { + + if ( ! extension_loaded( $extension ) ) { + $missing_extensions[] = $extension; + } + } + + return $missing_extensions; + } + + + /** + * Gets the required PHP extensions. + * + * @since 5.2.0 + * + * @return array + */ + public function get_php_extensions() { + + return $this->php_extensions; + } + + + /** + * Gets any missing PHP functions. + * + * @since 5.2.0 + * + * @return array + */ + public function get_missing_php_functions() { + + $missing_functions = []; + + foreach ( $this->get_php_functions() as $function ) { + + if ( ! extension_loaded( $function ) ) { + $missing_functions[] = $function; + } + } + + return $missing_functions; + } + + + /** + * Gets the required PHP functions. + * + * @since 5.2.0 + * + * @return array + */ + public function get_php_functions() { + + return $this->php_functions; + } + + + /** + * Gets any incompatible PHP settings. + * + * @since 5.2.0 + * + * @return array + */ + public function get_incompatible_php_settings() { + + $incompatible_settings = []; + + if ( function_exists( 'ini_get' ) ) { + + foreach ( $this->get_php_settings() as $setting => $expected ) { + + $actual = ini_get( $setting ); + + if ( ! $actual ) { + continue; + } + + if ( is_int( $expected ) ) { + + // determine if this is a size string, like "10MB" + $is_size = ! is_numeric( substr( $actual, -1 ) ); + + $actual_num = $is_size ? wc_let_to_num( $actual ) : $actual; + + if ( $actual_num < $expected ) { + + $incompatible_settings[ $setting ] = [ + 'expected' => $is_size ? size_format( $expected ) : $expected, + 'actual' => $is_size ? size_format( $actual_num ) : $actual, + 'type' => 'min', + ]; + } + + } elseif ( $actual !== $expected ) { + + $incompatible_settings[ $setting ] = [ + 'expected' => $expected, + 'actual' => $actual, + ]; + } + } + } + + return $incompatible_settings; + } + + + /** + * Gets the required PHP settings. + * + * @since 5.2.0 + * + * @return array + */ + public function get_php_settings() { + + return $this->php_settings; + } + + + /** + * Gets the plugin instance. + * + * @since 5.2.0 + * + * @return SV_WC_Plugin + */ + protected function get_plugin() { + + return $this->plugin; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-exception.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-exception.php new file mode 100644 index 0000000..e9f97ed --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-exception.php @@ -0,0 +1,38 @@ +id = $id; + $this->version = $version; + + $args = wp_parse_args( $args, [ + 'text_domain' => '', + 'supports_hpos' => false, + 'dependencies' => [], + ] ); + + $this->text_domain = $args['text_domain']; + $this->supports_hpos = $args['supports_hpos']; + + // includes that are required to be available at all times + $this->includes(); + + // initialize the dependencies manager + $this->init_dependencies( $args['dependencies'] ); + + // build the admin message handler instance + $this->init_admin_message_handler(); + + // build the admin notice handler instance + $this->init_admin_notice_handler(); + + // build the hook deprecator instance + $this->init_hook_deprecator(); + + // build the lifecycle handler instance + $this->init_lifecycle_handler(); + + // build the REST API handler instance + $this->init_rest_api_handler(); + + // build the setup handler instance + $this->init_setup_wizard_handler(); + + // add the action & filter hooks + $this->add_hooks(); + } + + + /** Init methods **********************************************************/ + + + /** + * Initializes the plugin dependency handler. + * + * @since 5.2.0 + * + * @param array $dependencies { + * PHP extension, function, and settings dependencies + * + * @type array $php_extensions PHP extension dependencies + * @type array $php_functions PHP function dependencies + * @type array $php_settings PHP settings dependencies + * } + */ + protected function init_dependencies( $dependencies ) { + + $this->dependency_handler = new SV_WC_Plugin_Dependencies( $this, $dependencies ); + } + + + /** + * Builds the admin message handler instance. + * + * Plugins can override this with their own handler. + * + * @since 5.2.0 + */ + protected function init_admin_message_handler() { + + $this->message_handler = new SV_WP_Admin_Message_Handler( $this->get_id() ); + } + + + /** + * Builds the admin notice handler instance. + * + * Plugins can override this with their own handler. + * + * @since 5.2.0 + */ + protected function init_admin_notice_handler() { + + $this->admin_notice_handler = new SV_WC_Admin_Notice_Handler( $this ); + } + + + /** + * Builds the hook deprecator instance. + * + * Plugins can override this with their own handler. + * + * @since 5.2.0 + */ + protected function init_hook_deprecator() { + + $this->hook_deprecator = new SV_WC_Hook_Deprecator( $this->get_plugin_name(), array_merge( $this->get_framework_deprecated_hooks(), $this->get_deprecated_hooks() ) ); + } + + + /** + * Builds the lifecycle handler instance. + * + * Plugins can override this with their own handler to perform install and + * upgrade routines. + * + * @since 5.2.0 + */ + protected function init_lifecycle_handler() { + + $this->lifecycle_handler = new Plugin\Lifecycle( $this ); + } + + + /** + * Builds the REST API handler instance. + * + * Plugins can override this to add their own data and/or routes. + * + * @since 5.2.0 + */ + protected function init_rest_api_handler() { + + $this->rest_api_handler = new REST_API( $this ); + } + + + /** + * Builds the Setup Wizard handler instance. + * + * Plugins can override and extend this method to add their own setup wizard. + * + * @since 5.3.0 + */ + protected function init_setup_wizard_handler() { + + require_once( $this->get_framework_path() . '/admin/abstract-sv-wc-plugin-admin-setup-wizard.php' ); + } + + + /** + * Adds the action & filter hooks. + * + * @since 5.2.0 + */ + private function add_hooks() { + + // initialize the plugin + add_action( 'plugins_loaded', array( $this, 'init_plugin' ), 15 ); + + // initialize the plugin admin + add_action( 'admin_init', array( $this, 'init_admin' ), 0 ); + + // hook for translations separately to ensure they're loaded + add_action( 'init', array( $this, 'load_translations' ) ); + + // handle HPOS compatibility + add_action( 'before_woocommerce_init', [ $this, 'handle_hpos_compatibility' ] ); + + // add the admin notices + add_action( 'admin_notices', array( $this, 'add_admin_notices' ) ); + add_action( 'admin_footer', array( $this, 'add_delayed_admin_notices' ) ); + + // add a 'Configure' link to the plugin action links + add_filter( 'plugin_action_links_' . plugin_basename( $this->get_plugin_file() ), array( $this, 'plugin_action_links' ) ); + + // automatically log HTTP requests from SV_WC_API_Base + $this->add_api_request_logging(); + + // add any PHP incompatibilities to the system status report + add_filter( 'woocommerce_system_status_environment_rows', array( $this, 'add_system_status_php_information' ) ); + } + + + /** + * Cloning instances is forbidden due to singleton pattern. + * + * @since 3.1.0 + */ + public function __clone() { + /* translators: Placeholders: %s - plugin name */ + _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'You cannot clone instances of %s.', 'woocommerce-plugin-framework' ), esc_html( $this->get_plugin_name() ) ), '3.1.0' ); + } + + + /** + * Unserializing instances is forbidden due to singleton pattern. + * + * @since 3.1.0 + */ + public function __wakeup() { + /* translators: Placeholders: %s - plugin name */ + _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'You cannot unserialize instances of %s.', 'woocommerce-plugin-framework' ), esc_html( $this->get_plugin_name() ) ), '3.1.0' ); + } + + + /** + * Load plugin & framework text domains. + * + * @internal + * + * @since 4.2.0 + */ + public function load_translations() { + + $this->load_framework_textdomain(); + + // if this plugin passes along its text domain, load its translation files + if ( $this->text_domain ) { + $this->load_plugin_textdomain(); + } + } + + + /** + * Loads the framework textdomain. + * + * @since 4.5.0 + */ + protected function load_framework_textdomain() { + $this->load_textdomain( 'woocommerce-plugin-framework', dirname( plugin_basename( $this->get_framework_file() ) ) ); + } + + + /** + * Loads the plugin textdomain. + * + * @since 4.5.0 + */ + protected function load_plugin_textdomain() { + $this->load_textdomain( $this->text_domain, dirname( plugin_basename( $this->get_plugin_file() ) ) ); + } + + + /** + * Loads the plugin textdomain. + * + * @since 4.5.0 + * @param string $textdomain the plugin textdomain + * @param string $path the i18n path + */ + protected function load_textdomain( $textdomain, $path ) { + + // user's locale if in the admin for WP 4.7+, or the site locale otherwise + $locale = is_admin() && is_callable( 'get_user_locale' ) ? get_user_locale() : get_locale(); + + $locale = apply_filters( 'plugin_locale', $locale, $textdomain ); + + load_textdomain( $textdomain, WP_LANG_DIR . '/' . $textdomain . '/' . $textdomain . '-' . $locale . '.mo' ); + + load_plugin_textdomain( $textdomain, false, untrailingslashit( $path ) . '/i18n/languages' ); + } + + + /** + * Initializes the plugin. + * + * Plugins can override this to set up any handlers after WordPress is ready. + * + * @since 5.2.0 + */ + public function init_plugin() { + + // stub + } + + + /** + * Initializes the plugin admin. + * + * Plugins can override this to set up any handlers after the WordPress admin is ready. + * + * @since 5.2.0 + */ + public function init_admin() { + + // stub + } + + + /** + * Include any critical files which must be available as early as possible, + * + * @since 2.0.0 + */ + private function includes() { + + $framework_path = $this->get_framework_path(); + + // common exception class + require_once( $framework_path . '/class-sv-wc-plugin-exception.php' ); + + // addresses + require_once( $framework_path . '/Addresses/Address.php' ); + require_once( $framework_path . '/Addresses/Customer_Address.php' ); + + // Settings API + require_once( $framework_path . '/Settings_API/Abstract_Settings.php' ); + require_once( $framework_path . '/Settings_API/Setting.php' ); + require_once( $framework_path . '/Settings_API/Control.php' ); + + // common utility methods + require_once( $framework_path . '/class-sv-wc-helper.php' ); + require_once( $framework_path . '/Country_Helper.php' ); + require_once( $framework_path . '/admin/Notes_Helper.php' ); + + // backwards compatibility for older WC versions + require_once( $framework_path . '/class-sv-wc-plugin-compatibility.php' ); + require_once( $framework_path . '/compatibility/abstract-sv-wc-data-compatibility.php' ); + require_once( $framework_path . '/compatibility/class-sv-wc-order-compatibility.php' ); + require_once( $framework_path . '/compatibility/class-sv-wc-subscription-compatibility.php' ); + + // generic API base + require_once( $framework_path . '/api/class-sv-wc-api-exception.php' ); + require_once( $framework_path . '/api/class-sv-wc-api-base.php' ); + require_once( $framework_path . '/api/interface-sv-wc-api-request.php' ); + require_once( $framework_path . '/api/interface-sv-wc-api-response.php' ); + + // XML API base + require_once( $framework_path . '/api/abstract-sv-wc-api-xml-request.php' ); + require_once( $framework_path . '/api/abstract-sv-wc-api-xml-response.php' ); + + // JSON API base + require_once( $framework_path . '/api/abstract-sv-wc-api-json-request.php' ); + require_once( $framework_path . '/api/abstract-sv-wc-api-json-response.php' ); + + // Cacheable API + require_once( $framework_path . '/api/traits/Cacheable_Request_Trait.php' ); + require_once( $framework_path . '/api/Abstract_Cacheable_API_Base.php' ); + + // REST API Controllers + require_once( $framework_path . '/rest-api/Controllers/Settings.php' ); + + // Handlers + require_once( $framework_path . '/Handlers/Script_Handler.php' ); + require_once( $framework_path . '/class-sv-wc-plugin-dependencies.php' ); + require_once( $framework_path . '/class-sv-wc-hook-deprecator.php' ); + require_once( $framework_path . '/class-sv-wp-admin-message-handler.php' ); + require_once( $framework_path . '/class-sv-wc-admin-notice-handler.php' ); + require_once( $framework_path . '/Lifecycle.php' ); + require_once( $framework_path . '/rest-api/class-sv-wc-plugin-rest-api.php' ); + } + + + /** + * Gets a list of framework deprecated/removed hooks. + * + * @see SV_WC_Plugin::init_hook_deprecator() + * @see SV_WC_Plugin::get_deprecated_hooks() + * + * @since 5.8.0 + * + * @return array associative array + */ + private function get_framework_deprecated_hooks() { + + $plugin_id = $this->get_id(); + $deprecated_hooks = []; + $deprecated_filters = [ + /** @see SV_WC_Payment_Gateway_My_Payment_Methods handler - once migrated to WC core tokens UI, we removed these and have no replacement */ + // TODO: remove deprecated hooks handling by version 6.0.0 or by 2021-02-25 {FN 2020-02-25} + "wc_{$plugin_id}_my_payment_methods_table_html", + "wc_{$plugin_id}_my_payment_methods_table_head_html", + "wc_{$plugin_id}_my_payment_methods_table_title", + "wc_{$plugin_id}_my_payment_methods_table_title_html", + "wc_{$plugin_id}_my_payment_methods_table_row_html", + "wc_{$plugin_id}_my_payment_methods_table_body_html", + "wc_{$plugin_id}_my_payment_methods_table_body_row_data", + "wc_{$plugin_id}_my_payment_methods_table_method_expiry_html", + "wc_{$plugin_id}_my_payment_methods_table_actions_html", + ]; + + foreach ( $deprecated_filters as $deprecated_filter ) { + $deprecated_hooks[ $deprecated_filter ] = [ + 'removed' => true, + 'replacement' => false, + 'version' => '5.8.1' + ]; + } + + return $deprecated_hooks; + } + + + /** + * Gets a list of the plugin's deprecated/removed hooks. + * + * Implementing classes should override this and return an array of deprecated/removed hooks in the following format: + * + * $old_hook_name = array { + * @type string $version version the hook was deprecated/removed in + * @type bool $removed if present and true, the message will indicate the hook was removed instead of deprecated + * @type string|bool $replacement if present and a string, the message will indicate the replacement hook to use, + * otherwise (if bool and false) the message will indicate there is no replacement available. + * } + * + * @since 4.3.0 + * + * @return array + */ + protected function get_deprecated_hooks() { + + // stub method + return []; + } + + + /** Admin methods ******************************************************/ + + + /** + * Returns true if on the admin plugin settings page, if any + * + * @since 2.0.0 + * @return boolean true if on the admin plugin settings page + */ + public function is_plugin_settings() { + // optional method, not all plugins *have* a settings page + return false; + } + + + /** + * Adds admin notices upon initialization. + * + * @internal + * + * @since 3.0.0 + */ + public function add_admin_notices() { + // stub method + } + + + /** + * Convenience method to add delayed admin notices, which may depend upon + * some setting being saved prior to determining whether to render + * + * @since 3.0.0 + */ + public function add_delayed_admin_notices() { + // stub method + } + + + /** + * Return the plugin action links. This will only be called if the plugin + * is active. + * + * @since 2.0.0 + * @param array $actions associative array of action names to anchor tags + * @return array associative array of plugin action links + */ + public function plugin_action_links( $actions ) { + + $custom_actions = array(); + + // settings url(s) + if ( $this->get_settings_link( $this->get_id() ) ) { + $custom_actions['configure'] = $this->get_settings_link( $this->get_id() ); + } + + // documentation url if any + if ( $this->get_documentation_url() ) { + /* translators: Docs as in Documentation */ + $custom_actions['docs'] = sprintf( '%s', $this->get_documentation_url(), esc_html__( 'Docs', 'woocommerce-plugin-framework' ) ); + } + + // support url if any + if ( $this->get_support_url() ) { + $custom_actions['support'] = sprintf( '%s', $this->get_support_url(), esc_html_x( 'Support', 'noun', 'woocommerce-plugin-framework' ) ); + } + + // review url if any + if ( $this->get_reviews_url() ) { + $custom_actions['review'] = sprintf( '%s', $this->get_reviews_url(), esc_html_x( 'Review', 'verb', 'woocommerce-plugin-framework' ) ); + } + + // add the links to the front of the actions list + return array_merge( $custom_actions, $actions ); + } + + + /** + * Declares HPOS compatibility if the plugin is compatible with HPOS. + * + * @internal + * + * @since 5.11.0 + */ + public function handle_hpos_compatibility() { + + if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) { + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', $this->get_plugin_file(), $this->is_hpos_compatible() ); + } + } + + + /** Helper methods ******************************************************/ + + + /** + * Automatically log API requests/responses when using SV_WC_API_Base + * + * @since 2.2.0 + * @see SV_WC_API_Base::broadcast_request() + */ + public function add_api_request_logging() { + + if ( ! has_action( 'wc_' . $this->get_id() . '_api_request_performed' ) ) { + add_action( 'wc_' . $this->get_id() . '_api_request_performed', array( $this, 'log_api_request' ), 10, 2 ); + } + } + + + /** + * Log API requests/responses + * + * @since 2.2.0 + * @param array $request request data, see SV_WC_API_Base::broadcast_request() for format + * @param array $response response data + * @param string|null $log_id log to write data to + */ + public function log_api_request( $request, $response, $log_id = null ) { + + $this->log( "Request\n" . $this->get_api_log_message( $request ), $log_id ); + + if ( ! empty( $response ) ) { + $this->log( "Response\n" . $this->get_api_log_message( $response ), $log_id ); + } + } + + + /** + * Transform the API request/response data into a string suitable for logging + * + * @since 2.2.0 + * @param array $data + * @return string + */ + public function get_api_log_message( $data ) { + + $messages = array(); + + $messages[] = isset( $data['uri'] ) && $data['uri'] ? 'Request' : 'Response'; + + foreach ( (array) $data as $key => $value ) { + + if ( is_array( $value ) || ( is_object( $value ) && 'stdClass' === get_class( $value ) ) ) { + $value = print_r( (array) $value, true ); + } elseif ( is_bool( $value ) ) { + $value = wc_bool_to_string( $value ); + } + + $messages[] = trim( sprintf( '%s: %s', $key, $value ) ); + } + + return implode( "\n", $messages ) . "\n"; + } + + + /** + * Adds any PHP incompatibilities to the system status report. + * + * @since 4.5.0 + * + * @param array $rows WooCommerce system status rows + * @return array + */ + public function add_system_status_php_information( $rows ) { + + foreach ( $this->get_dependency_handler()->get_incompatible_php_settings() as $setting => $values ) { + + if ( isset( $values['type'] ) && 'min' === $values['type'] ) { + + // if this setting already has a higher minimum from another plugin, skip it + if ( isset( $rows[ $setting ]['expected'] ) && $values['expected'] < $rows[ $setting ]['expected'] ) { + continue; + } + + $note = __( '%1$s - A minimum of %2$s is required.', 'woocommerce-plugin-framework' ); + + } else { + + // if this requirement is already listed, skip it + if ( isset( $rows[ $setting ] ) ) { + continue; + } + + $note = __( 'Set as %1$s - %2$s is required.', 'woocommerce-plugin-framework' ); + } + + $note = sprintf( $note, $values['actual'], $values['expected'] ); + + $rows[ $setting ] = array( + 'name' => $setting, + 'note' => $note, + 'success' => false, + 'expected' => $values['expected'], // WC doesn't use this, but it's useful for us + ); + } + + return $rows; + } + + + /** + * Saves errors or messages to WooCommerce Log (woocommerce/logs/plugin-id-xxx.txt) + * + * @since 2.0.0 + * @param string $message error or message to save to log + * @param string $log_id optional log id to segment the files by, defaults to plugin id + */ + public function log( $message, $log_id = null ) { + + if ( is_null( $log_id ) ) { + $log_id = $this->get_id(); + } + + if ( ! is_object( $this->logger ) ) { + $this->logger = new \WC_Logger(); + } + + $this->logger->add( $log_id, $message ); + } + + + /** + * Require and instantiate a class + * + * @since 4.2.0 + * @param string $local_path path to class file in plugin, e.g. '/includes/class-wc-foo.php' + * @param string $class_name class to instantiate + * @return object instantiated class instance + */ + public function load_class( $local_path, $class_name ) { + + require_once( $this->get_plugin_path() . $local_path ); + + return new $class_name; + } + + + /** + * Determines if TLS v1.2 is required for API requests. + * + * Subclasses should override this to return true if TLS v1.2 is required. + * + * @since 5.5.2 + * + * @return bool + */ + public function require_tls_1_2() { + + return false; + } + + + /** + * Determines if TLS 1.2 is available. + * + * @since 5.5.2 + * + * @return bool + */ + public function is_tls_1_2_available() { + + // assume availability to avoid notices for unknown SSL types + $is_available = true; + + // check the cURL version if installed + if ( is_callable( 'curl_version' ) ) { + + $versions = curl_version(); + + // cURL 7.34.0 is considered the minimum version that supports TLS 1.2 + if ( version_compare( $versions['version'], '7.34.0', '<' ) ) { + $is_available = false; + } + } + + return $is_available; + } + + + /** + * Determines whether the plugin supports HPOS. + * + * @since 5.11.0 + * + * @return bool + */ + public function is_hpos_compatible() : bool + { + return $this->supports_hpos && SV_WC_Plugin_Compatibility::is_wc_version_gte('7.6'); + } + + + /** Getter methods ******************************************************/ + + + /** + * Gets the main plugin file. + * + * @since 5.0.0 + * + * @return string + */ + public function get_plugin_file() { + + $slug = dirname( plugin_basename( $this->get_file() ) ); + + return trailingslashit( $slug ) . $slug . '.php'; + } + + + /** + * The implementation for this abstract method should simply be: + * + * return __FILE__; + * + * @since 2.0.0 + * @return string the full path and filename of the plugin file + */ + abstract protected function get_file(); + + + /** + * Returns the plugin id + * + * @since 2.0.0 + * @return string plugin id + */ + public function get_id() { + return $this->id; + } + + + /** + * Returns the plugin id with dashes in place of underscores, and + * appropriate for use in frontend element names, classes and ids + * + * @since 2.0.0 + * @return string plugin id with dashes in place of underscores + */ + public function get_id_dasherized() { + return str_replace( '_', '-', $this->get_id() ); + } + + + /** + * Returns the plugin full name including "WooCommerce", ie + * "WooCommerce X". This method is defined abstract for localization purposes + * + * @since 2.0.0 + * @return string plugin name + */ + abstract public function get_plugin_name(); + + + /** Handler methods *******************************************************/ + + + /** + * Gets the dependency handler. + * + * @since 5.2.0.1 + * + * @return SV_WC_Plugin_Dependencies + */ + public function get_dependency_handler() { + + return $this->dependency_handler; + } + + + /** + * Gets the lifecycle handler instance. + * + * @since 5.1.0 + * + * @return Plugin\Lifecycle + */ + public function get_lifecycle_handler() { + + return $this->lifecycle_handler; + } + + + /** + * Gets the Setup Wizard handler instance. + * + * @since 5.3.0 + * + * @return null|Admin\Setup_Wizard + */ + public function get_setup_wizard_handler() { + + return $this->setup_wizard_handler; + } + + + /** + * Gets the admin message handler. + * + * @since 2.0.0 + * + * @return SV_WP_Admin_Message_Handler + */ + public function get_message_handler() { + + return $this->message_handler; + } + + + /** + * Gets the admin notice handler instance. + * + * @since 3.0.0 + * + * @return SV_WC_Admin_Notice_Handler + */ + public function get_admin_notice_handler() { + + return $this->admin_notice_handler; + } + + + /** + * Gets the settings API handler instance. + * + * Plugins can use this to init the settings API handler. + * + * @since 5.7.0 + * + * @return void|Settings_API\Abstract_Settings + */ + public function get_settings_handler() { + + return; + } + + + /** + * Returns the plugin version name. Defaults to wc_{plugin id}_version + * + * @since 2.0.0 + * @return string the plugin version name + */ + public function get_plugin_version_name() { + + return 'wc_' . $this->get_id() . '_version'; + } + + + /** + * Returns the current version of the plugin + * + * @since 2.0.0 + * @return string plugin version + */ + public function get_version() { + return $this->version; + } + + + /** + * Returns the "Configure" plugin action link to go directly to the plugin + * settings page (if any) + * + * @since 2.0.0 + * @see SV_WC_Plugin::get_settings_url() + * @param string $plugin_id optional plugin identifier. Note that this can be a + * sub-identifier for plugins with multiple parallel settings pages + * (ie a gateway that supports both credit cards and echecks) + * @return string plugin configure link + */ + public function get_settings_link( $plugin_id = null ) { + + $settings_url = $this->get_settings_url( $plugin_id ); + + if ( $settings_url ) { + return sprintf( '%s', $settings_url, esc_html__( 'Configure', 'woocommerce-plugin-framework' ) ); + } + + // no settings + return ''; + } + + + /** + * Gets the plugin configuration URL + * + * @since 2.0.0 + * @see SV_WC_Plugin::get_settings_link() + * @param string $plugin_id optional plugin identifier. Note that this can be a + * sub-identifier for plugins with multiple parallel settings pages + * (ie a gateway that supports both credit cards and echecks) + * @return string plugin settings URL + */ + public function get_settings_url( $plugin_id = null ) { + + // stub method + return ''; + } + + + /** + * Returns true if the current page is the admin general configuration page + * + * @since 3.0.0 + * @return boolean true if the current page is the admin general configuration page + */ + public function is_general_configuration_page() { + + return isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] && ( ! isset( $_GET['tab'] ) || 'general' === $_GET['tab'] ); + } + + + /** + * Returns the admin configuration url for the admin general configuration page + * + * @since 3.0.0 + * @return string admin configuration url for the admin general configuration page + */ + public function get_general_configuration_url() { + + return admin_url( 'admin.php?page=wc-settings&tab=general' ); + } + + + /** + * Gets the plugin documentation url, used for the 'Docs' plugin action + * + * @since 2.0.0 + * @return string documentation URL + */ + public function get_documentation_url() { + + return null; + } + + + /** + * Gets the support URL, used for the 'Support' plugin action link + * + * @since 4.0.0 + * @return string support url + */ + public function get_support_url() { + + return null; + } + + + /** + * Gets the plugin sales page URL. + * + * @since 5.1.0 + * + * @return string + */ + public function get_sales_page_url() { + + return ''; + } + + + /** + * Gets the plugin reviews page URL. + * + * Used for the 'Reviews' plugin action and review prompts. + * + * @since 5.1.0 + * + * @return string + */ + public function get_reviews_url() { + + return $this->get_sales_page_url() ? $this->get_sales_page_url() . '#comments' : ''; + } + + + /** + * Gets the plugin's path without a trailing slash. + * + * e.g. /path/to/wp-content/plugins/plugin-directory + * + * @since 2.0.0 + * + * @return string + */ + public function get_plugin_path() { + + if ( null === $this->plugin_path ) { + $this->plugin_path = untrailingslashit( plugin_dir_path( $this->get_file() ) ); + } + + return $this->plugin_path; + } + + + /** + * Gets the plugin's URL without a trailing slash. + * + * E.g. http://skyverge.com/wp-content/plugins/plugin-directory + * + * @since 2.0.0 + * + * @return string + */ + public function get_plugin_url() { + + if ( null === $this->plugin_url ) { + $this->plugin_url = untrailingslashit( plugins_url( '/', $this->get_file() ) ); + } + + return $this->plugin_url; + } + + + /** + * Gets the woocommerce uploads path, without trailing slash. + * + * Oddly WooCommerce core does not provide a way to get this. + * + * @since 2.0.0 + * + * @return string + */ + public static function get_woocommerce_uploads_path() { + + $upload_dir = wp_upload_dir(); + + return $upload_dir['basedir'] . '/woocommerce_uploads'; + } + + + /** + * Returns the loaded framework __FILE__ + * + * @since 4.0.0 + * @return string + */ + public function get_framework_file() { + + return __FILE__; + } + + + /** + * Gets the loaded framework path, without trailing slash. + * + * This matches the path to the highest version of the framework currently loaded. + * + * @since 4.0.0 + * @return string + */ + public function get_framework_path() { + + return untrailingslashit( plugin_dir_path( $this->get_framework_file() ) ); + } + + + /** + * Gets the absolute path to the loaded framework image directory, without a trailing slash. + * + * @since 4.0.0 + * + * @return string + */ + public function get_framework_assets_path() { + + return $this->get_framework_path() . '/assets'; + } + + + /** + * Gets the loaded framework assets URL without a trailing slash. + * + * @since 4.0.0 + * + * @return string + */ + public function get_framework_assets_url() { + + return untrailingslashit( plugins_url( '/assets', $this->get_framework_file() ) ); + } + + + /** + * Gets the plugin default template path, without a trailing slash. + * + * @since 5.5.0 + * + * @return string + */ + public function get_template_path() { + + if ( null === $this->template_path ) { + $this->template_path = $this->get_plugin_path() . '/templates'; + } + + return $this->template_path; + } + + + /** + * Loads and outputs a template file HTML. + * + * @see \wc_get_template() except we define automatically the default path + * + * @since 5.5.0 + * + * @param string $template template name/part + * @param array $args associative array of optional template arguments + * @param string $path optional template path, can be empty, as themes can override this + * @param string $default_path optional default template path, will normally use the plugin's own template path unless overridden + */ + public function load_template( $template, array $args = [], $path = '', $default_path = '' ) { + + if ( '' === $default_path || ! is_string( $default_path ) ) { + $default_path = trailingslashit( $this->get_template_path() ); + } + + wc_get_template( $template, $args, $path, $default_path ); + } + + + /** + * Determines whether a plugin is active. + * + * @since 2.0.0 + * + * @param string $plugin_name plugin name, as the plugin-filename.php + * @return boolean true if the named plugin is installed and active + */ + public function is_plugin_active( $plugin_name ) { + + $is_active = false; + + if ( is_string( $plugin_name ) ) { + + if ( ! array_key_exists( $plugin_name, $this->active_plugins ) ) { + + $active_plugins = (array) get_option( 'active_plugins', array() ); + + if ( is_multisite() ) { + $active_plugins = array_merge( $active_plugins, array_keys( get_site_option( 'active_sitewide_plugins', array() ) ) ); + } + + $plugin_filenames = array(); + + foreach ( $active_plugins as $plugin ) { + + if ( SV_WC_Helper::str_exists( $plugin, '/' ) ) { + + // normal plugin name (plugin-dir/plugin-filename.php) + list( , $filename ) = explode( '/', $plugin ); + + } else { + + // no directory, just plugin file + $filename = $plugin; + } + + $plugin_filenames[] = $filename; + } + + $this->active_plugins[ $plugin_name ] = in_array( $plugin_name, $plugin_filenames, true ); + } + + $is_active = (bool) $this->active_plugins[ $plugin_name ]; + } + + return $is_active; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wp-admin-message-handler.php b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wp-admin-message-handler.php new file mode 100644 index 0000000..08a9351 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wp-admin-message-handler.php @@ -0,0 +1,438 @@ +add_message( 'Hello World!' ); + * ` + * + * Then show the messages wherever you need, either with the built-in method + * or by writing your own: + * + * `$admin_message_handler->show_messages();` + * + * @version 1.0.1 + */ +class SV_WP_Admin_Message_Handler { + + + /** transient message prefix */ + const MESSAGE_TRANSIENT_PREFIX = '_wp_admin_message_'; + + /** the message id GET name */ + const MESSAGE_ID_GET_NAME = 'wpamhid'; + + + /** @var string unique message identifier, defaults to __FILE__ unless otherwise set */ + private $message_id; + + /** @var array array of messages */ + private $messages = array(); + + /** @var array array of error messages */ + private $errors = array(); + + /** @var array array of warning messages */ + private $warnings = array(); + + /** @var array array of info messages */ + private $infos = array(); + + + /** + * Construct and initialize the admin message handler class + * + * @since 1.0.0 + * @param string $message_id optional message id. Best practice is to set + * this to a unique identifier based on the client plugin, such as __FILE__ + */ + public function __construct( $message_id = null ) { + + $this->message_id = $message_id; + + // load any available messages + $this->load_messages(); + + add_filter( 'wp_redirect', array( $this, 'redirect' ), 1, 2 ); + } + + + /** + * Persist messages + * + * @since 1.0.0 + * @return boolean true if any messages were set, false otherwise + */ + public function set_messages() { + + // any messages to persist? + if ( $this->message_count() > 0 || $this->info_count() > 0 || $this->warning_count() > 0 || $this->error_count() > 0 ) { + + set_transient( + self::MESSAGE_TRANSIENT_PREFIX . $this->get_message_id(), + array( + 'errors' => $this->errors, + 'warnings' => $this->warnings, + 'infos' => $this->infos, + 'messages' => $this->messages, + ), + 60 * 60 + ); + + return true; + } + + return false; + } + + + /** + * Loads messages + * + * @since 1.0.0 + */ + public function load_messages() { + + if ( isset( $_GET[ self::MESSAGE_ID_GET_NAME ] ) && $this->get_message_id() == $_GET[ self::MESSAGE_ID_GET_NAME ] ) { + + $memo = get_transient( self::MESSAGE_TRANSIENT_PREFIX . $_GET[ self::MESSAGE_ID_GET_NAME ] ); + + if ( isset( $memo['errors'] ) ) $this->errors = $memo['errors']; + if ( isset( $memo['warnings'] ) ) $this->warnings = $memo['warnings']; + if ( isset( $memo['infos'] ) ) $this->infos = $memo['infos']; + if ( isset( $memo['messages'] ) ) $this->messages = $memo['messages']; + + $this->clear_messages( $_GET[ self::MESSAGE_ID_GET_NAME ] ); + } + } + + + /** + * Clear messages and errors + * + * @since 1.0.0 + * @param string $id the messages identifier + */ + public function clear_messages( $id ) { + delete_transient( self::MESSAGE_TRANSIENT_PREFIX . $id ); + } + + + /** + * Add an error message. + * + * @since 1.0.0 + * @param string $error error message + */ + public function add_error( $error ) { + $this->errors[] = $error; + } + + + /** + * Adds a warning message. + * + * @since 5.1.0 + * + * @param string $message warning message to add + */ + public function add_warning( $message ) { + $this->warnings[] = $message; + } + + + /** + * Adds a info message. + * + * @since 5.1.0 + * + * @param string $message info message to add + */ + public function add_info( $message ) { + $this->infos[] = $message; + } + + + /** + * Add a message. + * + * @since 1.0.0 + * @param string $message the message to add + */ + public function add_message( $message ) { + $this->messages[] = $message; + } + + + /** + * Get error count. + * + * @since 1.0.0 + * @return int error message count + */ + public function error_count() { + return sizeof( $this->errors ); + } + + + /** + * Gets the warning message count. + * + * @since 5.1.0 + * + * @return int warning message count + */ + public function warning_count() { + return sizeof( $this->warnings ); + } + + + /** + * Gets the info message count. + * + * @since 5.1.0 + * + * @return int info message count + */ + public function info_count() { + return sizeof( $this->infos ); + } + + + /** + * Get message count. + * + * @since 1.0.0 + * @return int message count + */ + public function message_count() { + return sizeof( $this->messages ); + } + + + /** + * Get error messages + * + * @since 1.0.0 + * @return array of error message strings + */ + public function get_errors() { + return $this->errors; + } + + + /** + * Get an error message + * + * @since 1.0.0 + * @param int $index the error index + * @return string the error message + */ + public function get_error( $index ) { + return isset( $this->errors[ $index ] ) ? $this->errors[ $index ] : ''; + } + + + /** + * Gets all warning messages. + * + * @since 5.1.0 + * + * @return array + */ + public function get_warnings() { + return $this->warnings; + } + + + /** + * Gets a specific warning message. + * + * @since 5.1.0 + * + * @param int $index warning message index + * @return string + */ + public function get_warning( $index ) { + return isset( $this->warnings[ $index ] ) ? $this->warnings[ $index ] : ''; + } + + + /** + * Gets all info messages. + * + * @since 5.1.0 + * + * @return array + */ + public function get_infos() { + return $this->infos; + } + + + /** + * Gets a specific info message. + * + * @since 5.0.0 + * + * @param int $index info message index + * @return string + */ + public function get_info( $index ) { + return isset( $this->infos[ $index ] ) ? $this->infos[ $index ] : ''; + } + + + /** + * Get messages + * + * @since 1.0.0 + * @return array of message strings + */ + public function get_messages() { + return $this->messages; + } + + + /** + * Get a message + * + * @since 1.0.0 + * @param int $index the message index + * @return string the message + */ + public function get_message( $index ) { + return isset( $this->messages[ $index ] ) ? $this->messages[ $index ] : ''; + } + + + /** + * Render the errors and messages. + * + * @since 1.0.0 + * @param array $params { + * Optional parameters. + * + * @type array $capabilities Any user capabilities to check if the user is allowed to view the messages, + * default: `manage_woocommerce` + * } + */ + public function show_messages( $params = array() ) { + + $params = wp_parse_args( $params, array( + 'capabilities' => array( + 'manage_woocommerce', + ), + ) ); + + $check_user_capabilities = array(); + + // check if user has at least one capability that allows to see messages + foreach ( $params['capabilities'] as $capability ) { + $check_user_capabilities[] = current_user_can( $capability ); + } + + // bail out if user has no minimum capabilities to see messages + if ( ! in_array( true, $check_user_capabilities, true ) ) { + return; + } + + $output = ''; + + if ( $this->error_count() > 0 ) { + $output .= '
    • ' . implode( '
    • ', $this->get_errors() ) . '
    '; + } + + if ( $this->warning_count() > 0 ) { + $output .= '
    • ' . implode( '
    • ', $this->get_warnings() ) . '
    '; + } + + if ( $this->info_count() > 0 ) { + $output .= '
    • ' . implode( '
    • ', $this->get_infos() ) . '
    '; + } + + if ( $this->message_count() > 0 ) { + $output .= '
    • ' . implode( '
    • ', $this->get_messages() ) . '
    '; + } + + echo wp_kses_post( $output ); + } + + + /** + * Redirection hook which persists messages into session data. + * + * @since 1.0.0 + * @param string $location the URL to redirect to + * @param int $status the http status + * @return string the URL to redirect to + */ + public function redirect( $location, $status ) { + + // add the admin message id param to the + if ( $this->set_messages() ) { + $location = add_query_arg( self::MESSAGE_ID_GET_NAME, $this->get_message_id(), $location ); + } + + return $location; + } + + + /** + * Generate a unique id to identify the messages + * + * @since 1.0.0 + * @return string unique identifier + */ + protected function get_message_id() { + + if ( ! isset( $this->message_id ) ) $this->message_id = __FILE__; + + return wp_create_nonce( $this->message_id ); + + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/abstract-sv-wc-data-compatibility.php b/vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/abstract-sv-wc-data-compatibility.php new file mode 100644 index 0000000..5142550 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/abstract-sv-wc-data-compatibility.php @@ -0,0 +1,43 @@ +get_formatted_meta_data( $hide_prefix, $include_all ); + $item_meta = []; + + foreach ( $meta_data as $meta ) { + + $item_meta[] = array( + 'label' => $meta->display_key, + 'value' => $meta->value, + ); + } + + } else { + + $item_meta = new \WC_Order_Item_Meta( $item ); + $item_meta = $item_meta->get_formatted( $hide_prefix ); + } + + return $item_meta; + } + + + /** + * Gets the orders screen admin URL according to HPOS availability. + * + * @since 5.11.0 + * + * @return string + */ + public static function get_orders_screen_url() : string { + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + return admin_url( 'admin.php?page=wc-orders' ); + } + + return admin_url( 'edit.php?post_type=shop_order' ); + } + + + /** + * Gets the admin Edit screen URL for an order according to HPOS compatibility. + * + * @NOTE consider using {@see \WC_Order::get_edit_order_url()} whenever possible + * + * @see OrderUtil::get_order_admin_edit_url() + * @see PageController::get_edit_url() + * + * @since 5.0.1 + * + * @param \WC_Order|int $order order object or ID + * @return string + */ + public static function get_edit_order_url( $order ) : string { + + $order_id = $order instanceof \WC_Order ? $order->get_id() : $order; + $order_id = max((int) $order_id, 0); + + if ( SV_WC_Plugin_Compatibility::is_wc_version_gte( '3.3' ) ) { + $order_url = OrderUtil::get_order_admin_edit_url( $order_id ); + } else { + $order_url = apply_filters( 'woocommerce_get_edit_order_url', admin_url( 'post.php?post=' . absint( $order_id ) ) . '&action=edit', $order ); + } + + return $order_url; + } + + + /** + * Determines if the current admin screen is for the orders. + * + * @since 5.11.0 + * + * @return bool + */ + public static function is_orders_screen() : bool { + + $current_screen = SV_WC_Helper::get_current_screen(); + + if ( ! $current_screen ) { + return false; + } + + if ( ! SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + return 'edit-shop_order' === $current_screen->id; + } + + return static::get_order_screen_id() === $current_screen->id + && isset( $_GET['page'] ) + && $_GET['page'] === 'wc-orders' + && ! static::is_order_edit_screen(); + } + + + /** + * Determines if the current orders screen is for orders of a specific status. + * + * @since 5.11.0 + * + * @param string|string[] $status one or more statuses to compare + * @return bool + */ + public static function is_orders_screen_for_status( $status ) : bool { + global $post_type, $post_status; + + if ( ! SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + if ( 'shop_order' !== $post_type ) { + return false; + } + + return empty( $status ) || in_array( $post_status, (array) $status, true ); + } + + if ( ! static::is_orders_screen() ) { + return false; + } + + return empty( $status ) || ( isset( $_GET['status'] ) && in_array( $_GET['status'], (array) $status, true ) ); + } + + + /** + * Determines if the current admin screen is for adding or editing an order. + * + * @since 5.11.0 + * + * @return bool + */ + public static function is_order_edit_screen() : bool { + + $current_screen = SV_WC_Helper::get_current_screen(); + + if ( ! $current_screen ) { + return false; + } + + if ( ! SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + return 'shop_order' === $current_screen->id; + } + + return static::get_order_screen_id() === $current_screen->id + && isset( $_GET['page'], $_GET['action'] ) + && $_GET['page'] === 'wc-orders' + && in_array( $_GET['action'], [ 'new', 'edit' ], true ); + } + + + /** + * Determines if the current admin page is for any kind of order screen. + * + * @since 5.11.0 + * + * @return bool + */ + public static function is_order_screen() : bool { + + return static::is_orders_screen() + || static::is_order_edit_screen(); + } + + + /** + * Gets the ID of the order for the current edit screen. + * + * @since 5.11.0 + * + * @return int|null + */ + public static function get_order_id_for_order_edit_screen() : ?int { + global $post, $theorder; + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + return $theorder instanceof \WC_Abstract_Order && ! $theorder instanceof \WC_Subscription && static::is_order_edit_screen() + ? $theorder->get_id() + : null; + } + + return $post->ID ?? null; + } + + + /** + * Gets the admin screen ID for orders. + * + * This method detects the expected orders screen ID according to HPOS availability. + * `shop_order` as a registered post type as the screen ID is no longer used when HPOS is active. + * + * @see OrderUtil::get_order_admin_screen() + * @see COTMigrationUtil::get_order_admin_screen() + * + * @since 5.11.0 + * + * @return string + */ + public static function get_order_screen_id() : string { + + if ( is_callable( OrderUtil::class . '::get_order_admin_screen' ) ) { + return OrderUtil::get_order_admin_screen(); + } elseif ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + return function_exists( 'wc_get_page_screen_id' ) ? wc_get_page_screen_id( 'shop-order' ) : 'woocommerce_page_wc-orders'; + } + + return 'shop_order'; + } + + + /** + * Gets the orders table. + * + * @return string + */ + public static function get_orders_table() : string + { + global $wpdb; + + return SV_WC_Plugin_Compatibility::is_hpos_enabled() + ? OrdersTableDataStore::get_orders_table_name() + : $wpdb->posts; + } + + + /** + * Gets the orders meta table. + * + * @return string + */ + public static function get_orders_meta_table() : string + { + global $wpdb; + + return SV_WC_Plugin_Compatibility::is_hpos_enabled() + ? OrdersTableDataStore::get_meta_table_name() + : $wpdb->postmeta; + } + + + /** + * Determines whether a given identifier is a WooCommerce order or not, according to HPOS availability. + * + * @see OrderUtil::get_order_type() + * + * @since 5.11.0 + * + * @param int|\WP_Post|\WC_Order|null $post_order_or_id identifier of a possible order + * @param string|string[] $order_type the order type, defaults to shop_order, can specify multiple types + * @return bool + */ + public static function is_order( $post_order_or_id, $order_type = 'shop_order' ) : bool { + + if ( ! $post_order_or_id ) { + return false; + } + + if ( $post_order_or_id instanceof \WC_Subscription ) { + + return false; + + } elseif ( $post_order_or_id instanceof \WC_Abstract_Order ) { + + $found_type = $post_order_or_id->get_type(); + + } elseif ( ! SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + $found_type = is_numeric( $post_order_or_id ) || $post_order_or_id instanceof \WP_Post ? get_post_type( $post_order_or_id ) : null; + + } else { + + $found_type = OrderUtil::get_order_type( $post_order_or_id ); + } + + return $found_type && in_array( $found_type, (array) $order_type, true ); + } + + + /** + * Determines whether a given identifier is a WooCommerce refund or not, according to HPOS availability. + * + * @since 5.11.0 + * + * @param int|\WP_Post|\WC_Order|null $order_post_or_id identifier of a possible order + * @return bool + */ + public static function is_refund( $order_post_or_id ) : bool { + + return static::is_order( $order_post_or_id, 'shop_order_refund' ); + } + + + /** + * Gets the order meta according to HPOS availability. + * + * Uses {@see \WC_Order::get_meta()} if HPOS is enabled, otherwise it uses the WordPress {@see get_post_meta()} function. + * + * @since 5.11.0 + * + * @param int|\WC_Order $order order ID or object + * @param string $meta_key meta key + * @param bool $single return the first found meta with key (true), or all meta sharing the same key (default true) + * @return mixed + */ + public static function get_order_meta( $order, string $meta_key, bool $single = true ) { + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + $value = $single ? '' : []; + $order = is_numeric( $order ) && $order > 0 ? wc_get_order( (int) $order ) : $order; + + if ( $order instanceof \WC_Order ) { + $value = $order->get_meta( $meta_key, $single ); + } + + } else { + + $order_id = $order instanceof \WC_Order ? $order->get_id() : $order; + + $value = is_numeric( $order_id ) && $order_id > 0 ? get_post_meta( (int) $order_id, $meta_key, $single ) : false; + } + + return $value; + } + + + /** + * Updates the order meta according to HPOS availability. + * + * Uses {@see \WC_Order::update_meta_data()} if HPOS is enabled, otherwise it uses the WordPress {@see update_meta_data()} function. + * + * @since 5.11.0 + * + * @param int|\WC_Order $order order ID or object + * @param string $meta_key meta key + * @param mixed $meta_value meta value + */ + public static function update_order_meta( $order, string $meta_key, $meta_value ) { + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + $order = is_numeric( $order ) && $order > 0 ? wc_get_order( (int) $order ) : $order; + + if ( $order instanceof \WC_Order ) { + $order->update_meta_data( $meta_key, $meta_value ); + $order->save_meta_data(); + } + + } else { + + $order_id = $order instanceof \WC_Order ? $order->get_id() : $order; + + if ( is_numeric( $order_id ) && $order_id > 0 ) { + update_post_meta( (int) $order_id, $meta_key, $meta_value ); + } + } + } + + + /** + * Adds the order meta according to HPOS availability. + * + * Uses {@see \WC_Order::add_meta_data()} if HPOS is enabled, otherwise it uses the WordPress {@see add_meta_data()} function. + * + * @since 5.11.0 + * + * @param int|\WC_Order $order order ID or object + * @param string $meta_key meta key + * @param mixed $meta_value meta value + * @param bool $unique optional - whether the same key should not be added (default false) + */ + public static function add_order_meta( $order, string $meta_key, $meta_value, bool $unique = false ) { + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + $order = is_numeric( $order ) && $order > 0 ? wc_get_order( (int) $order ) : $order; + + if ( $order instanceof \WC_Order ) { + $order->add_meta_data( $meta_key, $meta_value, $unique ); + $order->save_meta_data(); + } + + } else { + + $order_id = $order instanceof \WC_Order ? $order->get_id() : $order; + + if ( is_numeric( $order_id ) && $order_id > 0 ) { + add_post_meta( (int) $order_id, $meta_key, $meta_value, $unique ); + } + } + } + + + /** + * Deletes the order meta according to HPOS availability. + * + * Uses {@see \WC_Order::delete_meta_data()} if HPOS is enabled, otherwise it uses the WordPress {@see delete_meta_data()} function. + * + * @since 5.11.0 + * + * @param int|\WC_Order $order order ID or object + * @param string $meta_key meta key + * @param mixed $meta_value optional (applicable if HPOS is inactive) + */ + public static function delete_order_meta( $order, string $meta_key, $meta_value = '' ) { + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + $order = is_numeric( $order ) && $order > 0 ? wc_get_order( (int) $order ) : $order; + + if ( $order instanceof \WC_Order ) { + $order->delete_meta_data( $meta_key); + $order->save_meta_data(); + } + + } else { + + $order_id = $order instanceof \WC_Order ? $order->get_id() : $order; + + if ( is_numeric( $order_id ) && $order_id > 0 ) { + delete_post_meta( (int) $order_id, $meta_key, $meta_value ); + } + } + } + + + /** + * Determines if an order meta exists according to HPOS availability. + * + * Uses {@see \WC_Order::meta_exists()} if HPOS is enabled, otherwise it uses the WordPress {@see metadata_exists()} function. + * + * @since 5.11.0 + * + * @param int|\WC_Order $order order ID or object + * @param string $meta_key meta key + * @return bool + */ + public static function order_meta_exists( $order, string $meta_key ) : bool { + + if ( SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + + $order = is_numeric( $order ) && $order > 0 ? wc_get_order( (int) $order ) : $order; + + if ( $order instanceof \WC_Order ) { + return $order->meta_exists( $meta_key ); + } + + } else { + + $order_id = $order instanceof \WC_Order ? $order->get_id() : $order; + + if ( is_numeric( $order_id ) && $order_id > 0 ) { + return metadata_exists( 'post', (int) $order_id, $meta_key ); + } + } + + return false; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/class-sv-wc-subscription-compatibility.php b/vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/class-sv-wc-subscription-compatibility.php new file mode 100644 index 0000000..d552a37 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/compatibility/class-sv-wc-subscription-compatibility.php @@ -0,0 +1,140 @@ +id; + } + + return static::get_subscripton_screen_id() === $current_screen->id + && isset( $_GET['page'], $_GET['action'] ) + && $_GET['page'] === 'wc-orders--shop_subscription' + && in_array( $_GET['action'], [ 'new', 'edit' ], true ); + } + + /** + * Determines if the current admin screen is for the subscriptions. + * + * @since 5.11.1 + * + * @return bool + */ + public static function is_subscriptions_screen() : bool { + + $current_screen = SV_WC_Helper::get_current_screen(); + + if ( ! $current_screen ) { + return false; + } + + if ( ! SV_WC_Plugin_Compatibility::is_hpos_enabled() ) { + return 'edit-shop_subscription' === $current_screen->id; + } + + return static::get_subscripton_screen_id() === $current_screen->id + && isset( $_GET['page'] ) + && $_GET['page'] === 'wc-orders--shop_subscription' + && ! static::is_subscription_edit_screen(); + } + + + /** + * Determines if the current admin page is for any kind of subscription screen. + * + * @since 5.11.1 + * + * @return bool + */ + public static function is_subscription_screen() : bool { + + return static::is_subscriptions_screen() + || static::is_subscription_edit_screen(); + } + + + /** + * Determines whether a given identifier is a WooCommerce subscription or not, according to HPOS availability. + * + * @since 5.11.1 + * + * @param int|\WP_Post|\WC_Subscription|null $post_subscription_or_id identifier of a possible subcription + * @return bool + */ + public static function is_subscription( $post_subscription_or_id ) : bool { + + if ( $post_subscription_or_id instanceof \WC_Subscription ) { + return true; + } + + return SV_WC_Order_Compatibility::is_order( $post_subscription_or_id, 'shop_subscription' ); + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.mo b/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.mo new file mode 100644 index 0000000000000000000000000000000000000000..467661176adb557c5cef3217a10411a2185c1614 GIT binary patch literal 19127 zcmcJW50G6|eaEjg{EH}pe?UOF1R@*E+a&}HSwPtAF0yPkiP=p;s;GD0ySsby-n;kt z?z_9h3Mg2yXq8GSRcR5MT8oO>DU7XDJFd+5XQZv2c5H3!v=uv2M`!wPuv2M2-*e8r z@4mO2kOccCXTSH)xxahP@BIFso9~^m=3bBAAJERFefk8?`w4i}3;4tD=@)t4I`F69 zE5UP5^Ssl+VNm_IgRcN1Q1|ZuuL2(g&j!B-UJd>fJPX|NV$VAd+y%Y{Y=N%^?+4EZ zm%)p`C&8D4FXUySdm*?1+y;tX18jj0fs5cdXV~XH1gifZgWU4I1B&ib;7h<$`Ex4h zgG|Y*fSbXqK+U5C>i%8emEe8gB>0!$>%sG0>Ur0L^WbIR=fGEiPl9@G&C6)u>EQFh zmxH=~HmLVq1d6q<1sRgJ4Lk+h1D*-K1r&dlK+XR?a3lCIxE}njyZ$_GUe5Vh;1+NP zsCmB!+yov1MenacSnvH9ybXK?gtgwS+|+wN2%Zdn7-Wjx$3cznQHNgv*K+=ZJO3L{ ze0mZb2LBg42^?l|Ukh#nHUER4_o5kI=e^)P;J3h= zz~Ca!I|2MMD1CYyWGddbLCx>qK*`mb0c-~NGEn@u02JSc!L8r~D7trm;@g=Bf!47C zLc-e#YTcH=UEs$-_4{`a757fzrtZIrKYDHgL^QlQh$?t@g5vK3p!)xjyZ;0zI!}Qo zf--)Ho_7+c`K$wZg*OChUi(4OJ?PHw1^?oCp7#g{OT0TP%nf`P)O)@S>iWNcqVu9b zYcH+<$2os9D7uHh8^EuEEQNO(N&-pmGEmRG71a9O1*-q!Apg84`NI-y;o= z@fJYQy9ay_{GP*iVuU2;>n=sNz`fv$!P~%>fOmtZfrr4g;2(l70KW`soxTZ*Unf9B z{5c1_0vrG(CjmGLegPZ<{|A)Zj9g~d{U9j1cY`N`9|cbV4}p@Ghe6T(Q}Bi0w?K{W zyYBo)pycPjLCMAGmplCj#h)8N@#P*+{g%ONz`q5r2G4%2m4h2W^>2gf_Zd*{`6_rP z_*bCjeG`M%I3rN<(FP?)2SJVV9#Hf77QFX;AOo$Ksp>9spkown4ec&PptGp*bjd#tJRvy=alH(yzeAo-_0B-^jS?|-J z=Jj3heDLI}tbSh%Vv4-2ASAsvfry}YAIK7VUk5J+pK;eWut?(H8$p)93qj5Aeh|^~ zKI_i^2^2s66ZFAnz=y!|UT4Si4e;fh{}gP1FGdK&w_Cuo!1sZg{~=KH9|g|^zYg+< z_XAMRufNvD7gvEH=kEr$gHM4sfLmay_<1`x4t^7SJ$O3C^e%8e$R+Rl;2q$rQ4Z@#5G=}r*UGQUsq_da(l_`Ey*EpP|zJ+ymh@1$u>F~NqH7lEjW*P-e65t`O;PAB{% z2l;Ou2XD+zz*}e!(cVgX7cHaRLA#l@iB_RqPrHhCFYOgH{j~NM(qxn0K$DI61noQ; zDq((;{QW5H!?Z)R&(QQ+Py00OLE4*XAEW&y?JcxXntuCfuQW&4IET{TD(x3&3pD9j z{+s6DCR#vycYYCkA8i-y1GEjay|mw@>32S@MO#CY?&x? zo<{R&ZCXmZofgx6l~(@!jyt&+d_QdutwF2PZlv}9-s>(T;2E@Wnrwr9zfHTq9NC=J z9eTgc!A9Es?!pXsD(!8wrn|Q2a9+56(}k&D@keSke^+p@8O9xdD(oyIHGeK?`|B^g zFwMJ+2CYuk4$bwQ?OND-cjcAc;anD5GW|DmQr87hBdiUVUX$NR=FCNZq}6ICi($~_lPVP2VQr%iuO(WY_CY_G z50H88nv6y20B>6m*L}B`-nOK(;Ehg?de(|q8RNwIfYF7ZJs)z~uK7+1%<;4s z9CZ%*qe;!(HtT3^?hV_~oa9c1djQ%SECFLu?bVu?))gRof5qY-=5n97<)UWZy@G~6 zu+&a)5sfgO?<}~HbbIB}XdX6Vqghp%RcUzsKrV!vwfdJ8qW3IM9abw=f36sd@qU)w zJ)<~0y}l=UDY@CMPd#gkksfCxtuEj=YGJhz#i8E}(=?b5jS|UMCl z3ui&GD!*orouc~_V;)_yd4EbWI2IOmnq#Rr(;9QrnsU?f#-dc-p@uc72AR~FNumLa zeIAiq3J!|lnGBR}(IE{xjB7sCqhhPD)u5lAH0#)-3&{K4OE>s)kvuNqpEJxGOR7BE z#_(dIu*zW!@va<3v9Y8_=#j5!KaI5GbSdvJZXF;Dw3GGR1!F4QEV;HAp%;n+y>W#) zPFts@hW78@;7!D7Hir&JiW3#y$q(mIS78&yKrMJ-2CK3YvYv*ceMWK6+a4&ENwT&# zHN^t&-|tNYG2&LZE*qDn-j1OWZwEX&-`_#B(re!QpjMN|JMw*^I{EluWt^x;_o$vN zMT9(4iU^4&Hh4Sd=DeLrE8VE^NL(<^##Q$ZcP@{8Q`cWsyc)!D(xGd+6X7cl`iqLf z%nF(Crif^A8J)`-4LGZ4+{TZCC2E}{spAt8zk#JIR;Tb-gWfLWbw{#fu<(sm%FVEi zlxh-=U-pSrds^+(LYq#zf`+J?e8PCn-q$lp=~mwgA|X}Oop20QlQYXh8q36zuQKm2 z#I0|`q!elny8>Kc*-9-%a48MLesi^gOeg9nMm!DzCa%nbm?5XO&~F4pY-WKtw!tU@ zn6-?jD@AoC({epfE|_CiK$_FH6j)KA93=ut0{t8eE4s z&4ga%5#`~tznk6)lX6)oGM3caO=Kn6+F_%}-qWM=Z!4e4ja`0cg(dC!?5%~nR=y{3 z+n&sO9Lua1p2%2ng^YQp+(k`WJ}eMpmIO2P(}g6%#uJ&6xmIy77$x7vOGIn4O%nj8c9@I#{$gT;p2$PzoLnO(q1ZS4Y z-5F_d(KK3*X-6!FG-(%zH#H#jl6kHf_uWY5jZ&D`Lc;_p$PBVX=sAsh!$_EjOwYI? zLg_MB(!86CU(BVM@#z_VYUkLvKfYsR+xGD>Z-(%sZlY+h!|0u1ZegU z$iXmZ9~TWX_@cIeWSJGqmDmjRShqm!%`T#-sQi-w_1WW zYZBFj99VY7Uy5L`6rcK-OaF>FHX@9;wVb*rom>b~YyzoII}8Y#y5)i6neAMn)K#vr)yU?Fue*Yza)(V& z7(r1S3T!FJR}LYIO~IiQSqz)8_Y<}Cn4*Z5lVvGYJ~CA&GB#6UIwIZNw-gy61ta5B zU=5RR5BfV*12VariDRQVsLC$}ZDTr(pInTH-4!vT1=OcHi}JjcQ_?Mr}yKbn&b_6q%P&B z#Ku6&eoI$NafS5f7{*krXa17DbYLZQ#qD0XM&5Hm7}{4bPraFLp_r0^VukV*Q?=R? z*YVG>Z$ce!kFr{6M32KPT^7^KX*YNpQp|=~&#PW}EalI&6AFXeD+&xA5ka2**}$8A4{OR1=qeVT5dVb$#RfFC>21wSF z_!E>aly$I**LV^EH`FSrB_*+#Y6F`MNFDn&6t7D?GGf3s$!zrY!}No?e9D3%!63G^ z*;+ADI}%Hh0)mNoOV-wwtQAelN?K93a;>m?mB4OR=`BWP(93xsN4LfVm*`3FRhJBS zW#?9sYLok{>50{QyNdD%#b=fuDY{ucK3&;klx#oT)(9zb^}I+=k1^QxD$h{Esj@HD zUirigquW+qoT9=Kws}!)<-NU>gFL$(`twj&RVUc-7zN{ z{hra5)X8zwl!*1%Mn6sFI!lUoODV{j8Md&zUWs!YwbdDK)u(o~lUimn6OY3K#Lbn7 zT4k?weZ&5~QKAmxHLq(2&2TAc*Vpb2HR#GzIv>?4+p_tzGLsDZ3!P3Y9UdAY8Q1N> zr6eKjHd`!%91JZ~ht}@eS<%**ylQ2PcxTwZ^pZ_mDwk}oT)M^Iv}ySAt(8l*Tyn`; zRj?|?eh?KU?O}fcchw|roC(+>sry&SeQ`e6G3VFLH>v*UEwAIzcs?Vesmz2ybJ!op zmc|j{GNAD>yrre3K_hd~TzIn?7+S7rr$eowrE0~-2$i{fwnGg^a475yZ79eO`(bD8 z)WpQ^x3r z5-d~aqmR4Q_uza$Qmq#p_Ss=O0PZIkH}jfsHduayyf`KEbor)DJv;e87*7*-ZAMX# z;y6;4S~FvTyN^E@)*}cm$RRHxGMT@){76U-OU8(TS>$}jAj`;j`8cZYik zuFfjE-P$vYh$4ZV2E`qs#pOe0%i-_?vi$8VKZdh1bMIvk{EtmUgwu%p<;NNbnQ94P z9ru+WN?~7rN9b8Z;K;rD_)zYAWJZJ)CpKku$QjaI*Jqa;KaBi@xrHHRd8;nuZ-y#( zAV`>g9XW<$!6E@f(8!Ps)TsfBkmIsGB9x^?i9;hmDZ3zS`Giy@>e`sc?bVQ6mD|UA z-Z{|SUEg3|Y*#%WVI41@EtUrP|2w!z^SUle26{H)dq=n!90+F1$<;-X%Z@PGR_)Q~ z$j`En*vwmxnaJnica{&a`xDi(23fw*EW=XPkmrmUd@@w->fFg9Z{|Y6Dw4)8M4z6)`GMZ z)zDjMqn&qVkF&OR!l*urdwkW>32MQhH*TUie=(X5$b^i{;vPxwv;=8~)zNZTxrQEu z(`;T}4p??axb~k14R&3$dx+P<>N7K=2C2ruMMTRfnl;OehY_G?wZQDjvn9{oM4PID zaYynF?488(fl+F2YWWc{wC2r-1@$E1$k~rVxV#zTrR=P{$$&sFatoQC@kN7s+TG4q z)OIdzyPbL0Ng~F$>RE=}4Hru)YUL@XZe{OSZy#A2%d=QP*&k>{b@(VbMleF8x2Jzs zeEa9OQYE@l>uC%nFZ|Cq9ZUQWHw@xtgV$H5l9>{AeS>J+fX|;A77NV$oGRW0?6!AKygY^+}Wk?L{_|^LvI#C9yXGPi1*8tdXn0?eSS#!w z3e>oQ&wF(FQElC$o$HJMt&=*}2!-oJpKKi4u9PtneLH3%SX32(&^L1HC?Ix2z&Koo zzAkjoeG;keo!LU+(FSq<|C5P{DSvum zdV1X7zI^}oiJ6g^J!9TTgqdW&(wSH#!x)s@q%uXzIjsy_)yK*z4iNBUt*pUEx2ryW zn9IJAgc8%Ch>hU0V3`=Xi5h_vNtMld2$QBYEFu;gm|IoE!Qvd?BKeLj8Rah7S&CzJ z$=%H2a8XG9hTQD9OsZ=($n6_S(q*4WQ|z?NYV`*+$3V)(+5I*Vm1hM|lU9!@Ji?fI z2_frQmM00%fl5HR4&!~yqZx^nY|G&Dzfx=krYMi-j!_VI!(@u^Gt&28aoDjH%9`); zi$YLMmBv5jm3NGBu0vBXF74QvVg=MN!%!$DAq${Dqews7lx*{1_qaA*YCYZY&Z6ti zU|ziuw4(eyM)JEa!925c;SFZDNs^-JQ;Ia1fQn|>a}Jith}!cpNwzKN zm&GMoj8OrTs@M{gE9h8fV*HQs!PpoygVIxP7}Bj#4J+?5ZwbiI%ti?ZCBcjqi9$=S zTIBZeziiToD&C`%Tt#FX3C^v#d`SE=>fy4xP8P>RVg3|_Cl?O88dXYeVjM8m@ey0t zp%jP3*8j~A3H+`3c0kfV#VpIEkl;0@=9b?_UUNB-Z*TLd1&*DXrIQ+*7cN`hr&)Sb zQB1A4H!LeFHDVx}6+id&FH^0PRxl4TOH(P#bri>ntR1`RPb(?OT{RXa#Qm^ad)TrW zIlJ?b*j<&$ZDHKWg;Vg7`Vex+O0(nYN|f4X$Z($If7Y4G&LMG0Pb@FP(dm#V6mNr@ zdLau+TD77u-=$CWf~}EU=0%2})_91O`N9qx+?Qkf{sMN-J%YDq-)|t&C|6^PGgnn} zbx8!ehBmU#gWzFD%<55h&?H@bk3vWHvN+p`@+(S?dK4#5f)pw9|S+@04arif=; zBB|xhqa4CWqalhEDRa#6|J_uvQLTo!m15;8S*5}d)87QZ6a-X7T|HOBJlcAyD|9wO zb}z5-e)7dHQ`9Dm3i)=GqD4NmdV@L$VYI1vue{B7-1ch$QxU}o43xef*g%X#QtPZ$ zzDm-5GuEPNLANpktk*8>wkdX%^>z|wq^N;xEgy>6GFIG~8s6COu%~=gqzrvQySHMS zzqG6GHu1;uJ$r4@PvI)vj=b4`AGiBFb^cdxZZtb=V_U)WI+#3Ld#A$1stu`56V<){ E1Ktq{X#fBK literal 0 HcmV?d00001 diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.po b/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.po new file mode 100644 index 0000000..642d0e2 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework-et.po @@ -0,0 +1,2296 @@ +# Copyright (C) 2015 +# This file is distributed under the same license as the package. +# Translators: +# Illimar Tambek , 2015 +msgid "" +msgstr "" +"Project-Id-Version: WC Plugin Framework\n" +"Report-Msgid-Bugs-To: https://support.woocommerce.com/hc/\n" +"POT-Creation-Date: 2023-06-05 02:06:50+00:00\n" +"PO-Revision-Date: 2017-03-27 11:59-0700\n" +"Last-Translator: Illimar Tambek \n" +"Language-Team: Estonian (http://www.transifex.com/projects/p/wc-plugin-" +"framework/language/et/)\n" +"Language: et\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: Poedit 1.8.11\n" + +#: Lifecycle.php:394 +msgid "Awesome" +msgstr "" + +#: Lifecycle.php:395 +msgid "Fantastic" +msgstr "" + +#: Lifecycle.php:396 +msgid "Cowabunga" +msgstr "" + +#: Lifecycle.php:397 +msgid "Congratulations" +msgstr "" + +#: Lifecycle.php:398 +msgid "Hot dog" +msgstr "" + +#. translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - +#. tag, %4$s - tag, %5$s - tag +#: Lifecycle.php:405 +msgid "" +"Are you having a great experience with %1$s so far? Please consider " +"%2$sleaving a review%3$s! If things aren't going quite as expected, we're " +"happy to help -- please %4$sreach out to our support team%5$s." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:182 +msgid "" +"Thanks for installing %1$s! To get started, take a minute to %2$sread the " +"documentation%3$s :)" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:210 +msgid "" +"Thanks for installing %1$s! To get started, take a minute to complete these " +"%2$squick and easy setup steps%3$s :)" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:235 +msgid "Setup" +msgstr "" + +#. translators: Placeholders: %s - plugin name +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:303 +msgid "%s › Setup" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:350 +#, fuzzy +msgid "Oops! An error occurred, please try again." +msgstr "Sinu päringuga esines viga, palun proovi uuesti." + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:488 +msgid "Ready!" +msgstr "" + +#. translators: Placeholder: %s - plugin name +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:581 +msgid "Welcome to %s!" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:594 +msgid "" +"This quick setup wizard will help you configure the basic settings and get " +"you started." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:608 +msgid "%s is ready!" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:660 +msgid "Next step" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:686 +msgid "You can also:" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:730 +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:760 +msgid "View the Docs" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:731 +msgid "See more setup options" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:732 +msgid "Learn more about customizing the plugin" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:756 +msgid "Review Your Settings" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:764 +msgid "Leave a Review" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:788 +msgid "Continue" +msgstr "Jätka" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:948 +msgid "Return to the WordPress Dashboard" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:950 +msgid "Not right now" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:952 +msgid "Skip this step" +msgstr "" + +#: class-sv-wc-framework-bootstrap.php:268 +msgid "" +"The following plugin is disabled because it is out of date and incompatible " +"with newer plugins on your site:" +msgid_plural "" +"The following plugins are disabled because they are out of date and " +"incompatible with newer plugins on your site:" +msgstr[0] "" +msgstr[1] "" + +#: class-sv-wc-framework-bootstrap.php:282 +msgid "" +"To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s " +"%5$sdeactivate%6$s the above plugin, or %7$sdeactivate the following%8$s:" +msgid_plural "" +"To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s " +"%5$sdeactivate%6$s the above plugins, or %7$sdeactivate the following%8$s:" +msgstr[0] "" +msgstr[1] "" + +#: class-sv-wc-framework-bootstrap.php:303 +msgid "" +"The following plugins are inactive because they require a newer version of " +"WooCommerce:" +msgstr "" +"Järgnevad pluginad ei ole aktiivsed, kuna vajavad korrektselt töötamiseks " +"uuemat WooCommerce'i versiooni:" + +#: class-sv-wc-framework-bootstrap.php:303 +msgid "" +"The following plugin is inactive because it requires a newer version of " +"WooCommerce:" +msgstr "" +"Järgnev plugin ei ole aktiivne, kuna vajab korrektselt töötamiseks uuemat " +"WooCommerce'i versiooni:" + +#. translators: Placeholders: %1$s - plugin name, %2$s - WooCommerce version +#. number +#: class-sv-wc-framework-bootstrap.php:308 +msgid "%1$s requires WooCommerce %2$s or newer" +msgstr "%1$s vajab WooCommerce'i versiooni %2$s või uuemat" + +#. translators: Placeholders: %1$s - tag, %2$s - tag +#: class-sv-wc-framework-bootstrap.php:312 +msgid "Please %1$supdate WooCommerce%2$s" +msgstr "Palun %1$suuenda WooCommerce'i%2$s" + +#: class-sv-wc-plugin-compatibility.php:217 +msgid "WooCommerce" +msgstr "" + +#. translators: Placeholders: %1$s - plugin name, %2$s - a PHP +#. extension/comma-separated list of PHP extensions +#: class-sv-wc-plugin-dependencies.php:156 +msgid "" +"%1$s requires the %2$s PHP extension to function. Contact your host or " +"server administrator to install and configure the missing extension." +msgid_plural "" +"%1$s requires the following PHP extensions to function: %2$s. Contact your " +"host or server administrator to install and configure the missing extensions." +msgstr[0] "" +msgstr[1] "" + +#. translators: Placeholders: %1$s - plugin name, %2$s - a PHP +#. function/comma-separated list of PHP functions +#: class-sv-wc-plugin-dependencies.php:184 +msgid "" +"%1$s requires the %2$s PHP function to exist. Contact your host or server " +"administrator to install and configure the missing function." +msgid_plural "" +"%1$s requires the following PHP functions to exist: %2$s. Contact your host " +"or server administrator to install and configure the missing functions." +msgstr[0] "" +msgstr[1] "" + +#. translators: Placeholders: %s - plugin name +#: class-sv-wc-plugin-dependencies.php:214 +msgid "" +"%s may behave unexpectedly because the following PHP configuration settings " +"are required:" +msgstr "" + +#: class-sv-wc-plugin-dependencies.php:228 +msgid "%s or higher" +msgstr "" + +#: class-sv-wc-plugin-dependencies.php:238 +msgid "" +"Please contact your hosting provider or server administrator to configure " +"these settings." +msgstr "" + +#. translators: Placeholders: %1$s - , %2$s - +#: class-sv-wc-plugin-dependencies.php:260 +msgid "" +"Hey there! We've noticed that your server is running %1$san outdated version " +"of PHP%2$s, which is the programming language that WooCommerce and its " +"extensions are built on.\n" +"\t\t\t\t\tThe PHP version that is currently used for your site is no longer " +"maintained, nor %1$sreceives security updates%2$s; newer versions are faster " +"and more secure.\n" +"\t\t\t\t\tAs a result, %3$s no longer supports this version and you should " +"upgrade PHP as soon as possible.\n" +"\t\t\t\t\tYour hosting provider can do this for you. %4$sHere are some " +"resources to help you upgrade%5$s and to explain PHP versions further." +msgstr "" + +#. translators: Placeholders: %s - plugin name +#: class-sv-wc-plugin.php:310 +msgid "You cannot clone instances of %s." +msgstr "%s eksemplari ei saa kloonida." + +#. translators: Placeholders: %s - plugin name +#: class-sv-wc-plugin.php:321 +msgid "You cannot unserialize instances of %s." +msgstr "%s eksemplari ei saa deserialiseerida (unserialize)." + +#. translators: Docs as in Documentation +#: class-sv-wc-plugin.php:594 +msgid "Docs" +msgstr "Dokumentatsioon" + +#: class-sv-wc-plugin.php:709 +msgid "%1$s - A minimum of %2$s is required." +msgstr "" + +#: class-sv-wc-plugin.php:718 +msgid "Set as %1$s - %2$s is required." +msgstr "" + +#: class-sv-wc-plugin.php:1011 +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:876 +msgid "Configure" +msgstr "Seadista" + +#: payment-gateway/External_Checkout/Admin.php:137 +#: payment-gateway/External_Checkout/Admin.php:147 +msgid "Processing Gateway" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:287 +msgid "Single products" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:288 +msgid "Cart" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:289 +#, fuzzy +msgid "Checkout" +msgstr "E-tšekk" + +#. translators: Placeholder: %s - external checkout label +#: payment-gateway/External_Checkout/Admin.php:330 +msgid "%s is disabled." +msgstr "" + +#. translators: Placeholders: %1$s - plugin name, %2$s - a +#. currency/comma-separated list of currencies, %3$s - tag, %4$s - +#. tag, %5$s - external checkout label +#: payment-gateway/External_Checkout/Admin.php:394 +msgid "" +"Accepts payment in %1$s only. %2$sConfigure%3$s WooCommerce to accept %1$s " +"to enable %4$s." +msgid_plural "" +"Accepts payment in one of %1$s only. %2$sConfigure%3$s WooCommerce to accept " +"one of %1$s to enable %4$s." +msgstr[0] "" +msgstr[1] "" + +#: payment-gateway/External_Checkout/Admin.php:436 +msgid "" +"%4$s%1$s Notice!%5$s Your store %2$scalculates taxes%3$s based on the " +"shipping address, but %1$s %4$sdoes not%5$s share customer shipping " +"information with your store for orders with only virtual products. These " +"orders will have their taxes calculated based on the shop address instead." +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:470 +msgid "" +"%4$s%1$s Notice!%5$s Your store %2$scalculates taxes%3$s based on the " +"billing address, but %1$s %4$sdoes not%5$s share the customer billing " +"address with your store before payment. These orders will have their taxes " +"calculated based on the shipping address (or shop address, for orders with " +"only virtual products)." +msgstr "" + +#: payment-gateway/External_Checkout/Frontend.php:259 +msgid "or" +msgstr "" + +#: payment-gateway/External_Checkout/Frontend.php:293 +msgid "" +"By submitting your payment, you agree to our %1$sterms and conditions%2$s." +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:71 +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:87 +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:66 +msgid "Google Pay" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:93 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:93 +#: payment-gateway/class-sv-wc-payment-gateway.php:1262 +msgid "Enable / Disable" +msgstr "Luba / Keela" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:94 +msgid "Accept Google Pay" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:101 +msgid "Allow Google Pay on" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:111 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:111 +msgid "Button Style" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:114 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:114 +msgid "Black" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:115 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:115 +msgid "White" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:148 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:150 +#: payment-gateway/class-sv-wc-payment-gateway.php:1440 +msgid "Connection Settings" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:157 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:188 +#, fuzzy +msgid "Test Mode" +msgstr "Veaotsingu režiim" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:158 +msgid "" +"Enable to test Google Pay functionality throughout your sites without " +"processing real payments." +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Frontend.php:130 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:141 +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:99 +msgid "An error occurred, please try again or try an alternate form of payment" +msgstr "Esines viga, palun proovi uuesti või kasuta teistsugust makseviisi" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:255 +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:380 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:539 +msgid "Subtotal" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:390 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:549 +#, fuzzy +msgid "Discount" +msgstr "Konto" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:400 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:559 +msgid "Shipping" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:410 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:569 +msgid "Fees" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:420 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:579 +msgid "Taxes" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:463 +#, fuzzy +msgid "Google Pay payment authorized." +msgstr "%1$s: makse ebaõnnestus (%2$s)" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:538 +#, fuzzy +msgid "Google Pay payment failed. %s" +msgstr "%1$s: makse ebaõnnestus (%2$s)" + +#: payment-gateway/External_Checkout/Orders.php:140 +#: payment-gateway/External_Checkout/Orders.php:153 +#: payment-gateway/External_Checkout/Orders.php:157 +msgid "Error %d: Unable to create order. Please try again." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:71 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:87 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:65 +msgid "Apple Pay" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:94 +msgid "Accept Apple Pay" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:101 +msgid "Allow Apple Pay on" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:116 +msgid "White with outline" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:159 +msgid "Apple Merchant ID" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:163 +msgid "This is found in your %1$sApple developer account%2$s" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:173 +msgid "Certificate Path" +msgstr "" + +#. translators: Placeholders: %s - the server's web root path +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:178 +msgid "For reference, your current web root path is: %s" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:189 +msgid "" +"Enable to test Apple Pay functionality throughout your sites without " +"processing real payments." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:228 +msgid "Your site must be served over HTTPS with a valid SSL certificate." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:238 +msgid "" +"Your %1$sMerchant Identity Certificate%2$s cannot be found. Please check " +"your path configuration." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:176 +msgid "Buy with" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:152 +msgid "Apple Pay payment authorized." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:186 +#, fuzzy +msgid "Apple Pay payment failed. %s" +msgstr "%1$s: makse ebaõnnestus (%2$s)" + +#: payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:179 +#, fuzzy +msgid "" +"There was a problem processing your order and it is being placed on hold for " +"review. Please contact us to complete the transaction." +msgstr "" +"Tellimus on pandud ülevaatuseks ootele. Tehingu sooritamiseks võta palun " +"meiega ühendust." + +#: payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:217 +#: payment-gateway/class-sv-wc-payment-gateway.php:2898 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:521 +msgid "" +"An error occurred, please try again or try an alternate form of payment." +msgstr "Esines viga, palun proovi uuesti või kasuta teistsugust makseviisi." + +#. translators: Placeholders: %s - a WooCommerce order ID +#: payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:320 +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:449 +msgid "Could not find order %s" +msgstr "" + +#. translators: Placeholders: %1$s - status code, %2$s - status message +#. translators: Placeholders: %1$s - payment request response status code, %2$s +#. - payment request response status message +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:152 +#: payment-gateway/class-sv-wc-payment-gateway.php:2487 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:172 +msgid "Status code %1$s: %2$s" +msgstr "Staatuse kood %1$s: %2$s" + +#. translators: Placeholders: %s - status code +#. translators: Placeholders: %s - payment request response status code +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:155 +#: payment-gateway/class-sv-wc-payment-gateway.php:2490 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:175 +msgid "Status code: %s" +msgstr "Staatuse kood: %s" + +#. translators: Placeholders; %s - status message +#. translators: Placeholders: %s - payment request response status message +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:158 +#: payment-gateway/class-sv-wc-payment-gateway.php:2493 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:178 +msgid "Status message: %s" +msgstr "Staatuse teade: %s" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:163 +#: payment-gateway/class-sv-wc-payment-gateway.php:2498 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:185 +msgid "Transaction ID %s" +msgstr "Tehingu ID %s" + +#. translators: Placeholders: %s - payment gateway title (such as +#. Authorize.net, Braintree, etc) +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:204 +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:513 +msgid "%s duplicate transaction received" +msgstr "%s: duplikaattehing" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:207 +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:516 +msgid "Order %s is already paid for." +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:267 +#: payment-gateway/class-sv-wc-payment-gateway.php:2834 +msgid "" +"Your order has been received and is being reviewed. Thank you for your " +"business." +msgstr "" +"Sinu tellimus on vastu võetud ja on ülevaatamisel. Täname koostöö eest." + +#. translators: This is a message describing that the transaction in question +#. only performed a credit card authorization and did not capture any funds. +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:274 +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:864 +#: payment-gateway/class-sv-wc-payment-gateway.php:1865 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:370 +msgid "Authorization only transaction" +msgstr "Autoriseerimise tehing" + +#. translators: Placeholders: %s - payment gateway title +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:364 +#, fuzzy +msgid "%s Transaction Held for Review" +msgstr "%1$s: tehning pandi ülevaatuseks ootele (%2$s)" + +#. translators: Placeholders: %s - payment gateway title +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:435 +#, fuzzy +msgid "%s Payment Failed" +msgstr "%1$s: makse ebaõnnestus (%2$s)" + +#. translators: Placeholders: %s - payment gateway title +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:462 +#, fuzzy +msgid "%s Transaction Cancelled" +msgstr "%1$s: tehing tühistatud (%2$s)" + +#: payment-gateway/Handlers/Capture.php:158 +msgid "Order cannot be captured" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:163 +msgid "Transaction authorization has expired" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:168 +msgid "Transaction has already been fully captured" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:173 +#, fuzzy +msgid "Transaction cannot be captured" +msgstr "Tehingu tüüp" + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - transaction amount. Definitions: +#. Capture, as in capture funds from a credit card. +#: payment-gateway/Handlers/Capture.php:189 +msgid "%1$s Capture of %2$s Approved" +msgstr "%1$s: tasumine summas %2$s kinnitatud" + +#. translators: Placeholders: %s - transaction ID +#: payment-gateway/Handlers/Capture.php:198 +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:683 +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:768 +#: payment-gateway/class-sv-wc-payment-gateway.php:2166 +#: payment-gateway/class-sv-wc-payment-gateway.php:2399 +#: payment-gateway/class-sv-wc-payment-gateway.php:2715 +#: payment-gateway/class-sv-wc-payment-gateway.php:2760 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:353 +msgid "(Transaction ID %s)" +msgstr "(Tehingu ID %s)" + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - failure message. Definitions: +#. "capture" as in capturing funds from a credit card. +#: payment-gateway/Handlers/Capture.php:229 +msgid "%1$s Capture Failed: %2$s" +msgstr "%1$s: makse teostamine ebaõnnestus: %2$s" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:130 +#, fuzzy +msgid "" +"Are you sure you wish to process this capture? The action cannot be undone." +msgstr "" +"Oled kindel, et soovid seda teha? Muudatust ei rakendata enne kui klikid " +"\"Uuenda\"" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:133 +msgid "" +"Something went wrong, and the capture could no be completed. Please try " +"again." +msgstr "" + +#. translators: verb, as in "Capture credit card charge". Used when an +#. amount has been pre-authorized before, but funds have not yet been captured +#. (taken) from the card. Capturing the charge will take the money from the +#. credit card and put it in the merchant's pockets. +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:178 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:267 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:330 +msgid "Capture Charge" +msgstr "Teosta makse" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:320 +msgid "This charge has been fully captured." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:322 +msgid "This charge can no longer be captured." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:324 +msgid "This charge cannot be captured." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:91 +msgid "Are you sure you want to remove this token?" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:101 +msgid "Invalid token data" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:105 +#, fuzzy +msgid "An error occurred. Please try again." +msgstr "Sinu päringuga esines viga, palun proovi uuesti." + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:491 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:305 +msgid "(%s)" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:521 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:900 +msgid "Default" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:557 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:590 +msgid "Token ID" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:562 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:300 +msgid "Card Type" +msgstr "Kaardi tüüp" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:567 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:603 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:192 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:298 +msgid "Last Four" +msgstr "Viimased 4 numbrit" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:574 +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:362 +msgid "Expiration (MM/YY)" +msgstr "Aegub (KK/AA)" + +#. translators: e-check account type, HTML form field label +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:595 +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:470 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:299 +msgid "Account Type" +msgstr "Konto tüüp" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:598 +msgid "Checking" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:599 +msgid "Savings" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:700 +msgid "Refresh" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:702 +msgid "Add New" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:705 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:297 +msgid "Save" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:728 +msgid "Remove" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:224 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:209 +msgid "%s Payment Tokens" +msgstr "%s maksevahendid" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:302 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:862 +msgid "Customer ID" +msgstr "Kliendi ID" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:32 +msgid "This section contains configuration settings for this gateway." +msgstr "" + +#. translators: environment as in a software environment (test/production) +#: payment-gateway/admin/views/html-admin-gateway-status.php:53 +#: payment-gateway/class-sv-wc-payment-gateway.php:1389 +msgid "Environment" +msgstr "Keskkond" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:54 +msgid "The transaction environment for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:61 +msgid "Tokenization Enabled" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:62 +msgid "Displays whether or not tokenization is enabled for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:75 +#: payment-gateway/class-sv-wc-payment-gateway.php:1316 +msgid "Debug Mode" +msgstr "Veaotsingu režiim" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:76 +msgid "Displays whether or not debug logging is enabled for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:79 +msgid "Display at Checkout & Log" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:81 +msgid "Display at Checkout" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:83 +#: payment-gateway/class-sv-wc-payment-gateway.php:1324 +msgid "Save to Log" +msgstr "Salvesta logifaili" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:85 +#: payment-gateway/class-sv-wc-payment-gateway.php:1322 +msgid "Off" +msgstr "Välja lülitatud" + +#: payment-gateway/admin/views/html-order-partial-capture.php:30 +#, fuzzy +msgid "Authorization total" +msgstr "Autoriseerimine" + +#: payment-gateway/admin/views/html-order-partial-capture.php:34 +msgid "Amount already captured" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:40 +msgid "Remaining order total" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:46 +#, fuzzy +msgid "Capture amount" +msgstr "Teosta makse" + +#: payment-gateway/admin/views/html-order-partial-capture.php:53 +msgid "Comment (optional):" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:65 +#, fuzzy +msgid "Capture %s" +msgstr "Teosta makse" + +#: payment-gateway/admin/views/html-order-partial-capture.php:66 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:608 +#, fuzzy +msgid "Cancel" +msgstr "Tühista tellimus" + +#: payment-gateway/admin/views/html-user-payment-token-editor-token.php:57 +msgid "-- Select an option --" +msgstr "" + +#: payment-gateway/admin/views/html-user-payment-token-editor.php:59 +msgid "No saved payment tokens" +msgstr "" + +#: payment-gateway/admin/views/html-user-profile-field-customer-id.php:30 +msgid "The gateway customer ID for the user. Only edit this if necessary." +msgstr "" +"Kasutajale makseviisi poolt määratud kliendi tunnus. Muuda seda ainult siis, " +"kui tõesti vajalik." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:100 +msgid "" +"We cannot process your order with the payment information that you provided. " +"Please use a different payment account or an alternate payment method." +msgstr "" +"Me ei saa sinu tellimust antud makseinfo alusel töödelda. Palun kasuta teist " +"maksekontot või teistsugust makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:101 +msgid "" +"This order is being placed on hold for review. Please contact us to complete " +"the transaction." +msgstr "" +"Tellimus on pandud ülevaatuseks ootele. Tehingu sooritamiseks võta palun " +"meiega ühendust." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:106 +msgid "" +"This order is being placed on hold for review due to an incorrect card " +"verification number. You may contact the store to complete the transaction." +msgstr "" +"Tellimus pandi ootele, kuna kaardi turvakood oli vale. Tehingu " +"lõpuleviimiseks võid poega ühendust võtta." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:107 +msgid "The card verification number is invalid, please try again." +msgstr "Kaardi turvakood on vale, palun proovi uuesti." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:108 +msgid "Please enter your card verification number and try again." +msgstr "Palun sisesta oma kaardi turvakood ja proovi uuesti." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:111 +msgid "" +"That card type is not accepted, please use an alternate card or other form " +"of payment." +msgstr "" +"Sellist tüüpi kaarti ei võeta vastu, palun proovi mõnda teist kaarti või " +"teistsugust makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:112 +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:116 +msgid "" +"The card type is invalid or does not correlate with the credit card number. " +"Please try again or use an alternate card or other form of payment." +msgstr "" +"Kaardi tüüp on vigane või ei vasta kaardi numbrile. Palun proovi uuesti, " +"proovi mõnda teist kaarti või teistsugust makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:113 +msgid "Please select the card type and try again." +msgstr "Palun vali kaardi tüüp ja proovi uuesti." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:117 +msgid "The card number is invalid, please re-enter and try again." +msgstr "Kaardi number on vigane, palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:118 +msgid "Please enter your card number and try again." +msgstr "Palun sisesta oma kaardi number ja proovi uuesti." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:121 +msgid "The card expiration date is invalid, please re-enter and try again." +msgstr "" +"Kaardi aegumiskuupäev on vale, palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:122 +msgid "The card expiration month is invalid, please re-enter and try again." +msgstr "Kaardi aegumise kuu on vale, palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:123 +msgid "The card expiration year is invalid, please re-enter and try again." +msgstr "" +"Kaardi aegumise aasta on vale, palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:124 +msgid "Please enter your card expiration date and try again." +msgstr "Palun sisesta oma kaardi aegumiskuupäev ja proovi uuesti." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:127 +msgid "The bank routing number is invalid, please re-enter and try again." +msgstr "" +"Panga suunakood ei ole korrektne, palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:128 +msgid "The bank account number is invalid, please re-enter and try again." +msgstr "" +"Pangakonto number ei ole korrektne, palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:131 +msgid "" +"The provided card is expired, please use an alternate card or other form of " +"payment." +msgstr "" +"Antud kaart on aegunud, palun kasuta mõnda teist kaarti või teistsugust " +"makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:132 +msgid "" +"The provided card was declined, please use an alternate card or other form " +"of payment." +msgstr "" +"Antud kaart klükati tagasi, palun kasuta mõnda teist kaarti või teistsugust " +"makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:133 +msgid "" +"Insufficient funds in account, please use an alternate card or other form of " +"payment." +msgstr "" +"Kontol pole piisavalt vahendeid, palun kasuta mõnda teist kaarti või " +"teistsugust makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:134 +msgid "" +"The card is inactivate or not authorized for card-not-present transactions, " +"please use an alternate card or other form of payment." +msgstr "" +"Antud kaart ei ole aktiveeritud või ei ole sellega internetimaksed lubatud. " +"Palun kasuta mõnda teist kaarti või teistsugust makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:135 +msgid "" +"The credit limit for the card has been reached, please use an alternate card " +"or other form of payment." +msgstr "" +"Kaardi krediitilimiit on ära kasutatud, palun kasuta mõnda teist kaarti või " +"teistsugust makseviisi." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:136 +msgid "" +"The card verification number does not match. Please re-enter and try again." +msgstr "Kaardi turvakood ei klapi. Palun sisesta uuesti ja proovi veelkord." + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:137 +msgid "" +"The provided address does not match the billing address for cardholder. " +"Please verify the address and try again." +msgstr "" +"Antud aadress ei kattu kaardi omaniku aadressiga. Palun kontrolli, et " +"sisestaid õige aadressi ning proovi uuesti." + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:61 +msgid "" +"Payment error, please try another payment method or contact us to complete " +"your transaction." +msgstr "" +"Viga maksega, palun proovi teistsugust makseviisi või võta meiega ühendust." + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:161 +#: payment-gateway/class-sv-wc-payment-gateway.php:503 +msgid "Card expiration date is invalid" +msgstr "Kaardi aegumiskuupäev ei ole korrektne" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:185 +#: payment-gateway/class-sv-wc-payment-gateway.php:496 +msgid "Card number is missing" +msgstr "Kaardi number on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:191 +#: payment-gateway/class-sv-wc-payment-gateway.php:499 +msgid "Card number is invalid (wrong length)" +msgstr "Kaardi number ei ole korrektne (pikkus on vale)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:196 +#: payment-gateway/class-sv-wc-payment-gateway.php:498 +msgid "Card number is invalid (only digits allowed)" +msgstr "Kaardi number ei ole korrektne (lubatud on ainult numbrid)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:201 +#: payment-gateway/class-sv-wc-payment-gateway.php:497 +msgid "Card number is invalid" +msgstr "Kaardi number ei ole korrektne" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:228 +#: payment-gateway/class-sv-wc-payment-gateway.php:501 +msgid "Card security code is invalid (only digits are allowed)" +msgstr "Kaardi turvakood ei ole korrektne (lubatud on ainult numbrid)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:234 +#: payment-gateway/class-sv-wc-payment-gateway.php:502 +msgid "Card security code is invalid (must be 3 or 4 digits)" +msgstr "Kaardi turvakood ei ole korrektne (peab olema 3 või 4 numbrit)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:240 +#: payment-gateway/class-sv-wc-payment-gateway.php:500 +msgid "Card security code is missing" +msgstr "Kaardi turvakood on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:267 +#: payment-gateway/class-sv-wc-payment-gateway.php:512 +msgid "Routing Number is missing" +msgstr "Suunakood on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:274 +#: payment-gateway/class-sv-wc-payment-gateway.php:513 +msgid "Routing Number is invalid (only digits are allowed)" +msgstr "Suunakood ei ole korrektne (lubatud on ainult numbrid)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:280 +#: payment-gateway/class-sv-wc-payment-gateway.php:514 +msgid "Routing number is invalid (must be 9 digits)" +msgstr "Suunakood ei ole korrektne (peab olemas 9 numbrit)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:289 +#: payment-gateway/class-sv-wc-payment-gateway.php:509 +msgid "Account Number is missing" +msgstr "Konto number on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:296 +#: payment-gateway/class-sv-wc-payment-gateway.php:510 +msgid "Account Number is invalid (only digits are allowed)" +msgstr "Konto number ei ole korrektne (lubatud on ainult numbrid)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:302 +#: payment-gateway/class-sv-wc-payment-gateway.php:511 +msgid "Account number is invalid (must be between 5 and 17 digits)" +msgstr "Konto number ei ole korrektne (peab olemas 5-17 numbrit)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:309 +#: payment-gateway/class-sv-wc-payment-gateway.php:508 +msgid "Drivers license number is invalid" +msgstr "Juhiloa number ei ole korrektne" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:315 +#: payment-gateway/class-sv-wc-payment-gateway.php:504 +msgid "Check Number is invalid (only digits are allowed)" +msgstr "Tšeki number ei ole korrektne (lubatud on ainult numbrid)" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:494 +#, fuzzy +msgid "Unknown error" +msgstr "Esines tundmatu viga" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:503 +#, fuzzy +msgid "Payment method address could not be updated. %s" +msgstr "Maksevahend kustutatud." + +#. translators: Placeholders: %1$s - payment method title, %2$s - payment +#. account type (savings/checking) (may or may not be available), %3$s - last +#. four digits of the account +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:673 +#: payment-gateway/class-sv-wc-payment-gateway.php:2750 +msgid "%1$s Check Transaction Approved: %2$s account ending in %3$s" +msgstr "%1$s: tšeki tehing vastu võetud: %2$s konto, lõpeb numbritega %3$s" + +#. translators: Placeholders: %s - check number +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:678 +#: payment-gateway/class-sv-wc-payment-gateway.php:2755 +msgid "Check number %s" +msgstr "Tšeki number %s" + +#. translators: Placeholders: %1$s - payment method title, %2$s - environment +#. ("Test"), %3$s - transaction type (authorization/charge), %4$s - card type +#. (mastercard, visa, ...), %5$s - last four digits of the card +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:747 +#, fuzzy +msgid "%1$s %2$s %3$s Approved: %4$s ending in %5$s" +msgstr "%1$s %2$s: %3$s kinnitatud: %4$s lõpeb numbritega %5$s (aegub %6$s)" + +#. translators: Placeholders: %s - expiry date +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:760 +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:718 +#: payment-gateway/class-sv-wc-payment-gateway.php:2707 +msgid "(expires %s)" +msgstr "(aegub %s)" + +#. translators: Placeholders: %s - failure message +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:832 +msgid "Tokenization Request Failed: %s" +msgstr "Maksevahendi salvestamise päring ebaõnnestus: %s" + +#. translators: Placeholders: %1$s - payment method title, %2$s - failure +#. message +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:843 +msgid "%1$s Tokenization Request Failed: %2$s" +msgstr "%1$s: maksevahendi salvestamise päring ebaõnnestus: %2$s" + +#. translators: Placeholders: %s - failure message. Payment method as in a +#. specific credit card, e-check or bank account +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:901 +msgid "Oops, adding your new payment method failed: %s" +msgstr "Oih, sinu maksevahendi lisamine ebaõnnestus: %s" + +#. translators: Payment method as in a specific credit card. Placeholders: %1$s +#. - card type (visa, mastercard, ...), %2$s - last four digits of the card, +#. %3$s - card expiry date +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:946 +msgid "Nice! New payment method added: %1$s ending in %2$s (expires %3$s)" +msgstr "" +"Lahe! Uus maksevahend lisatud: %1$s, lõpeb numbritega %2$s (aegub %3$s)" + +#. translators: Payment method as in a specific e-check account. Placeholders: +#. %1$s - account type (checking/savings), %2$s - last four digits of the +#. account +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:956 +msgid "Nice! New payment method added: %1$s account ending in %2$s" +msgstr "Lahe! Uus maksevahend lisatud: %1$s konto, lõpeb numbritega %2$s" + +#. translators: Payment method as in a specific credit card, e-check or bank +#. account +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:963 +msgid "Nice! New payment method added." +msgstr "Lahe! Uus maksevahend lisatud." + +#. translators: Placeholders: %1$s - site title, %2$s - customer email. Payment +#. method as in a specific credit card, e-check or bank account +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:1086 +msgid "%1$s - Add Payment Method for %2$s" +msgstr "%1$s - Lisa maksevahend kliendile %2$s" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:180 +msgid "PayPal" +msgstr "PayPal" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:181 +msgid "Checking Account" +msgstr "Tšekikonto" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:182 +msgid "Savings Account" +msgstr "Hoiuarve" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:183 +msgid "Credit / Debit Card" +msgstr "Deebet- või krediitkaart" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:184 +msgid "Bank Account" +msgstr "Pangakonto" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:301 +msgid "Thank you for your order, please click the button below to pay." +msgstr "Aitäh tellimuse eest. Palun kliki maksmiseks alloleval nupul." + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:302 +msgid "" +"Thank you for your order. We are now redirecting you to complete payment." +msgstr "Aitäh tellimuse eest. Makse teostamiseks suunatakse sind nüüd edasi." + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:303 +msgid "Pay Now" +msgstr "Maksa" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:304 +msgid "Cancel Order" +msgstr "Tühista tellimus" + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - payment method name (mastercard, bank +#. account, etc), %3$s - last four digits of the card/account, %4$s - +#. card/account expiry date +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:601 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:1114 +msgid "%1$s Payment Method Saved: %2$s ending in %3$s (expires %4$s)" +msgstr "" +"%1$s: maksevahend salvestatud: %2$s lõpeb numbritega in %3$s (aegub %4$s)" + +#. translators: Placeholders: %1$s - payment gateway title (such as CyberSouce, +#. NETbilling, etc), %2$s - account type (checking/savings - may or may not be +#. available), %3$s - last four digits of the account +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:612 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:1125 +msgid "%1$s eCheck Payment Method Saved: %2$s account ending in %3$s" +msgstr "" +"%1$s: e-tšeki maksevahend salvestatud: %2$s konto, lõpeb numbritega %3$s" + +#. translators: Placeholders: %s - payment gateway title (such as CyberSouce, +#. NETbilling, etc) +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:621 +#, fuzzy +msgid "%s Payment Method Saved" +msgstr "Minu maksevahendid." + +#. translators: Placeholders: %s - a failed tokenization API error +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:630 +#, fuzzy +msgid "Tokenization failed. %s" +msgstr "Maksevahendi salvestamise päring ebaõnnestus: %s" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:293 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:607 +msgid "Edit" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:337 +#: payment-gateway/class-sv-wc-payment-gateway.php:1269 +msgid "Title" +msgstr "Nimetus" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:340 +msgid "Details" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:343 +#, fuzzy +msgid "Default?" +msgstr "(vaikimisi)" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:609 +#, fuzzy +msgid "" +"Oops, there was an error updating your payment method. Please try again." +msgstr "Sinu päringuga esines viga, palun proovi uuesti." + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:610 +msgid "Are you sure you want to delete this payment method?" +msgstr "Oled sa kindel, et soovid selle maksevahendi kustutada?" + +#. translators: Payment method as in a specific credit card, eCheck or bank +#. account +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:697 +msgid "You do not have any saved payment methods." +msgstr "Sul ei ole salvestatud maksevahendeid." + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:872 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:200 +msgid "Nickname" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:1118 +msgid "Oops, you took too long, please try again." +msgstr "Oih, sul läks liiga kaua aega - palun proovi uuesti." + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:1129 +msgid "There was an error with your request, please try again." +msgstr "Sinu päringuga esines viga, palun proovi uuesti." + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:344 +msgid "Card Number" +msgstr "Kaardi number" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:365 +msgid "MM / YY" +msgstr "KK / AA" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:384 +msgid "Card Security Code" +msgstr "Kaardi turvakood" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:387 +msgid "CSC" +msgstr "Turvakood" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:427 +msgid "Where do I find this?" +msgstr "Kust ma selle leian?" + +#. translators: e-check routing number, HTML form field label, +#. https:en.wikipedia.org/wiki/Routing_transit_number +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:433 +msgid "Routing Number" +msgstr "Suunakood" + +#. translators: e-check account number, HTML form field label +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:452 +msgid "Account Number" +msgstr "Kontonumber" + +#. translators: Test mode refers to the current software environment +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:518 +msgid "TEST MODE ENABLED" +msgstr "TESTREŽIIM SISSE LÜLITATUD" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:545 +#, fuzzy +msgid "Sample Check" +msgstr "E-tšekk" + +#. translators: Payment method as in a specific credit card, eCheck or bank +#. account +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:620 +msgid "Manage Payment Methods" +msgstr "Halda maksevahendeid" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:757 +msgid "Use a new card" +msgstr "Kasuta uut kaarti" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:757 +msgid "Use a new bank account" +msgstr "Kasuta uut pangakontot" + +#. translators: account as in customer's account on the eCommerce site +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:820 +msgid "Securely Save to Account" +msgstr "Salvesta turvaliselt oma kontole" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:954 +#, fuzzy +msgid "Payment Info" +msgstr "Maksevahendid" + +#. translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - +#. tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:706 +#, fuzzy +msgid "" +"%1$s: WooCommerce is not being forced over SSL; your customers' payment data " +"may be at risk. %2$sVerify your site URLs here%3$s" +msgstr "" +"%s: WooCommerce'i ei sunnita SSLi kasutama; sinu klientide andmed võivad " +"olla ohus." + +#. translators: Placeholders: %s - payment gateway name +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:723 +msgid "" +"%s will soon require TLS 1.2 support to process transactions and your server " +"environment may need to be updated. Please contact your hosting provider to " +"confirm that your site can send and receive TLS 1.2 connections and request " +"they make any necessary updates." +msgstr "" + +#. translators: Placeholders: %1$s - plugin name, %2$s - a +#. currency/comma-separated list of currencies, %3$s - tag, %4$s - tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:779 +msgid "" +"%1$s accepts payment in %2$s only. %3$sConfigure%4$s WooCommerce to accept " +"%2$s to enable this gateway for checkout." +msgid_plural "" +"%1$s accepts payment in one of %2$s only. %3$sConfigure%4$s WooCommerce to " +"accept one of %2$s to enable this gateway for checkout." +msgstr[0] "" +msgstr[1] "" + +#. translators: Placeholders: %1$s - payment gateway name, %2$s - opening +#. tag, %3$s - closing tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:814 +msgid "" +"Heads up! %1$s is currently configured to log transaction data for debugging " +"purposes. If you are not experiencing any problems with payment processing, " +"we recommend %2$sturning off Debug Mode%3$s" +msgstr "" + +#. translators: Placeholders: %s - gateway name +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:865 +msgid "%s is not configured" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:877 +msgid "Dismiss" +msgstr "Loobu" + +#. translators: Placeholders: %1$s - plugin name, %2$s - opening HTML link +#. tag, %3$s - closing HTML link tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:914 +msgid "" +"Heads up! Apple Pay for %1$s requires WooCommerce version 3.2 or greater. " +"Please %2$supdate WooCommerce%3$s." +msgstr "" + +#. translators: Placeholders: %1$s - plugin name, %2$s - opening HTML link +#. tag, %3$s - closing HTML link tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:938 +msgid "" +"Heads up! Google Pay for %1$s requires WooCommerce version 3.2 or greater. " +"Please %2$supdate WooCommerce%3$s." +msgstr "" + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - tag, %3$s - tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:974 +msgid "" +"%1$s is inactive for subscription transactions. Please %2$senable " +"tokenization%3$s to activate %1$s for Subscriptions." +msgstr "" +"%1$s ei ole korduvtellimuste jaoks kasutatav. Palun %2$slülita " +"maksevahendite salvestamine%3$s sisse, et aktiveerida %1$s Korduvellimuste " +"(Subscriptions) jaoks." + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - tag, %3$s - tag +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:992 +msgid "" +"%1$s is inactive for pre-order transactions. Please %2$senable " +"tokenization%3$s to activate %1$s for Pre-Orders." +msgstr "" +"%1$s ei ole eeltellimuste maksete jaoks kasutatav. Palun %2$slülita " +"maksevahendite salvestamine%3$s sisse, et aktiveerida %1$s Eeltellimuste " +"(Pre-Orders) jaoks." + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:1029 +msgid "" +"You must enable tokenization for this gateway in order to support automatic " +"renewal payments with the WooCommerce Subscriptions extension." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:1030 +msgid "Inactive" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:115 +#, fuzzy +msgid "%s Customer ID" +msgstr "Kliendi ID" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:184 +#, fuzzy +msgid "Type" +msgstr "Kaardi tüüp" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:254 +msgid "Removed payment token \"%d\"" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:301 +#, fuzzy +msgid "Expiry Date" +msgstr "Aegumiskuupäev (01/%s)" + +#: payment-gateway/class-sv-wc-payment-gateway.php:350 +msgid "you successfully processed a payment!" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:355 +msgid "you successfully processed a refund!" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:505 +msgid "Check Number is missing" +msgstr "Tšeki number on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway.php:506 +msgid "Drivers license state is missing" +msgstr "Juhiloa osariik on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway.php:507 +msgid "Drivers license number is missing" +msgstr "Juhiloa number on puudu" + +#: payment-gateway/class-sv-wc-payment-gateway.php:720 +msgid "Continue to Payment" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:720 +msgid "Place order" +msgstr "Esita tellimus" + +#: payment-gateway/class-sv-wc-payment-gateway.php:752 +msgid "Thank you for your order." +msgstr "Aitäh tellimuse eest." + +#: payment-gateway/class-sv-wc-payment-gateway.php:1221 +msgid "Credit Card" +msgstr "Krediitkaart" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1223 +msgid "eCheck" +msgstr "E-tšekk" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1241 +msgid "Pay securely using your credit card." +msgstr "Maksa turvaliselt oma krediitkaardiga." + +#: payment-gateway/class-sv-wc-payment-gateway.php:1243 +msgid "Pay securely using your checking account." +msgstr "Maksa turvaliselt oma tšekikontoga." + +#: payment-gateway/class-sv-wc-payment-gateway.php:1263 +msgid "Enable this gateway" +msgstr "Lülita see makseviis sisse" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1271 +msgid "Payment method title that the customer will see during checkout." +msgstr "Kliendile kassas nähtav makseviisi nimetus." + +#: payment-gateway/class-sv-wc-payment-gateway.php:1276 +msgid "Description" +msgstr "Kirjeldus" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1278 +msgid "Payment method description that the customer will see during checkout." +msgstr "Kliendile kassas nähtav makseviisi kirjeldus." + +#: payment-gateway/class-sv-wc-payment-gateway.php:1307 +msgid "Detailed Decline Messages" +msgstr "Täpsemad maksest keeldumise teated" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1309 +msgid "" +"Check to enable detailed decline messages to the customer during checkout " +"when possible, rather than a generic decline message." +msgstr "" +"Lülita see valik sisse, kui soovid klientidele üldise maksest keeldumise " +"teate asemel näidata võimaluse korral täpsemaid põhjusi." + +#. translators: Placeholders: %1$s - tag, %2$s - tag +#: payment-gateway/class-sv-wc-payment-gateway.php:1319 +msgid "" +"Show Detailed Error Messages and API requests/responses on the checkout page " +"and/or save them to the %1$sdebug log%2$s" +msgstr "" +"Näita üksikasjalikke veateateud ja API päringuid/vastuseid kassas ja/või " +"salvesta need %1$slogifaili%2$s" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1323 +msgid "Show on Checkout Page" +msgstr "Näita kassas" + +#. translators: show debugging information on both checkout page and in the log +#: payment-gateway/class-sv-wc-payment-gateway.php:1326 +msgid "Both" +msgstr "Mõlemad" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1392 +msgid "Select the gateway environment to use for transactions." +msgstr "Vali makseviisi tehingute teostamise keskkond." + +#: payment-gateway/class-sv-wc-payment-gateway.php:1446 +msgid "Share connection settings" +msgstr "Jaga ühenduse andmeid" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1448 +msgid "Use connection/authentication settings from other gateway" +msgstr "Kasuta teise makseviisi ühenduse/autentimise seadeid" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1451 +msgid "Disabled because the other gateway is using these settings" +msgstr "Ei saa muuta, kuna teine makseviis kasutab neid seadeid" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1468 +msgid "Card Verification (CSC)" +msgstr "Kaardi turvakood (CSC)" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1469 +msgid "Display the Card Security Code (CV2) field on checkout" +msgstr "Näita kassas kaardi turvakoodi (CV2) välja" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1477 +#, fuzzy +msgid "Saved Card Verification" +msgstr "Kaardi turvakood (CSC)" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1478 +#, fuzzy +msgid "Display the Card Security Code field when paying with a saved card" +msgstr "Näita kassas kaardi turvakoodi (CV2) välja" + +#. translators: Placeholders: %1$s - site title, %2$s - order number +#: payment-gateway/class-sv-wc-payment-gateway.php:1813 +msgid "%1$s - Order %2$s" +msgstr "%1$s - Tellimus %2$s" + +#. translators: Placeholders: %1$s - site title, %2$s - order number. +#. Definitions: Capture as in capture funds from a credit card. +#: payment-gateway/class-sv-wc-payment-gateway.php:1947 +msgid "%1$s - Capture for Order %2$s" +msgstr "%1$s - Tasumine tellimuse %2$s eest" + +#. translators: Placeholders: %1$s - site title, %2$s - order number +#: payment-gateway/class-sv-wc-payment-gateway.php:2090 +msgid "%1$s - Refund for Order %2$s" +msgstr "%1$s - Tagasimakse tellimuse %2$s eest" + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - a monetary amount +#: payment-gateway/class-sv-wc-payment-gateway.php:2157 +msgid "%1$s Refund in the amount of %2$s approved." +msgstr "%1$s: tagasimakse summas %2$s kinnitatud." + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - error code, %3$s - error message +#: payment-gateway/class-sv-wc-payment-gateway.php:2187 +msgid "%1$s Refund Failed: %2$s - %3$s" +msgstr "%1$s: tagasimakse ebaõnnestus: %2$s - %3$s" + +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - error message +#: payment-gateway/class-sv-wc-payment-gateway.php:2195 +msgid "%1$s Refund Failed: %2$s" +msgstr "%1$s: tagasimakse ebaõnnestus: %2$s" + +#. translators: Placeholders: %s - payment gateway title (such as +#. Authorize.net, Braintree, etc) +#: payment-gateway/class-sv-wc-payment-gateway.php:2216 +msgid "%s Order completely refunded." +msgstr "%s: tellimus täielikult tagasi makstud." + +#: payment-gateway/class-sv-wc-payment-gateway.php:2271 +msgid "" +"Oops, you cannot partially void this order. Please use the full order amount." +msgstr "" +"Oih, sa ei saa seda tellimust osaliselt tühistada. Palun kasuta tellimuse " +"täissummat." + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error code, +#. %3$s - error message. Void as in to void an order. +#: payment-gateway/class-sv-wc-payment-gateway.php:2358 +msgid "%1$s Void Failed: %2$s - %3$s" +msgstr "%1$s: tühistamine ebaõnnestus: %2$s - %3$s" + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error +#. message. Void as in to void an order. +#: payment-gateway/class-sv-wc-payment-gateway.php:2366 +msgid "%1$s Void Failed: %2$s" +msgstr "%1$s: tühistamine ebaõnnestus: %2$s" + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - a monetary +#. amount. Void as in to void an order. +#: payment-gateway/class-sv-wc-payment-gateway.php:2390 +msgid "%1$s Void in the amount of %2$s approved." +msgstr "%1$s: tühistamine summas %2$s kinnitatud." + +#. translators: Placeholders: %1$s - payment method title, %2$s - environment +#. ("Test"), %3$s - transaction type (authorization/charge) +#: payment-gateway/class-sv-wc-payment-gateway.php:2686 +#, fuzzy +msgid "%1$s %2$s %3$s Approved" +msgstr "%1$s: %2$s tehing kinnitatud" + +#. translators: Placeholders: %1$s - credit card type (MasterCard, Visa, +#. etc...), %2$s - last four digits of the card +#: payment-gateway/class-sv-wc-payment-gateway.php:2696 +msgid "%1$s ending in %2$s" +msgstr "" + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - message +#. (probably reason for the transaction being held for review) +#: payment-gateway/class-sv-wc-payment-gateway.php:2792 +msgid "%1$s Transaction Held for Review (%2$s)" +msgstr "%1$s: tehning pandi ülevaatuseks ootele (%2$s)" + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error +#. message; e.g. Order Note: [Payment method] Payment failed [error] +#: payment-gateway/class-sv-wc-payment-gateway.php:2881 +msgid "%1$s Payment Failed (%2$s)" +msgstr "%1$s: makse ebaõnnestus (%2$s)" + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - +#. message/error +#: payment-gateway/class-sv-wc-payment-gateway.php:2916 +msgid "%1$s Transaction Cancelled (%2$s)" +msgstr "%1$s: tehing tühistatud (%2$s)" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3164 +msgid "Transaction Type" +msgstr "Tehingu tüüp" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3166 +msgid "" +"Select how transactions should be processed. Charge submits all transactions " +"for settlement, Authorization simply authorizes the order total for capture " +"later." +msgstr "" +"Vali, kuidas peaks tehinguid töötlema. \"Makse\" saadab kõik tehingud " +"koheselt tasumisele, \"Autoriseerimine\" lihtsalt autoriseerib tellimuse " +"summa hilisemaks tasumiseks." + +#: payment-gateway/class-sv-wc-payment-gateway.php:3177 +msgid "Charge Virtual-Only Orders" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3179 +msgid "" +"If the order contains exclusively virtual items, enable this to immediately " +"charge, rather than authorize, the transaction." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3187 +#, fuzzy +msgid "Enable Partial Capture" +msgstr "Lülita see makseviis sisse" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3189 +msgid "Allow orders to be partially captured multiple times." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3201 +#, fuzzy +msgid "Capture Paid Orders" +msgstr "Teosta makse" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3204 +msgid "Automatically capture orders when they are changed to %s." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3205 +msgid "a paid status" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3395 +#, fuzzy +msgid "Accepted Card Logos" +msgstr "Vastuvõetavad kaardid" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3397 +#, fuzzy +msgid "" +"These are the card logos that are displayed to customers as accepted during " +"checkout." +msgstr "Kliendile kassas nähtav makseviisi nimetus." + +#. translators: Placeholders: %1$s - tag, %2$s - tag +#: payment-gateway/class-sv-wc-payment-gateway.php:3400 +msgid "" +"This setting %1$sdoes not%2$s change which card types the gateway will " +"accept. Accepted cards are configured from your payment processor account." +msgstr "" + +#. translators: +#. http:www.cybersource.com/products/payment_security/payment_tokenization/ and +#. https:en.wikipedia.org/wiki/Tokenization_(data_security) +#: payment-gateway/class-sv-wc-payment-gateway.php:3491 +msgid "Tokenization" +msgstr "Maksevahendite salvestamine" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3492 +msgid "" +"Allow customers to securely save their payment details for future checkout." +msgstr "" +"Võimalda klientidel oma makseandmeid edaspidisteks tehinguteks turvaliselt " +"talletada." + +#. translators: %1$s - gateway name, %2$s - tag, %3$s - tag, %4$s - +#. tag, %5$s - tag +#: payment-gateway/class-sv-wc-payment-gateway.php:4277 +msgid "" +"Heads up! %1$s is not fully configured and cannot accept payments. Please " +"%2$sreview the documentation%3$s and configure the %4$sgateway settings%5$s." +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:261 +msgid "Pre-Order Tokenization attempt failed (%s)" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:307 +msgid "%s - Pre-Order Release Payment for Order %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:311 +msgid "Payment token missing/invalid." +msgstr "Maksevahend on puudu või vigane." + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:336 +msgid "%s %s Pre-Order Release Payment Approved: %s ending in %s (expires %s)" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:347 +msgid "%s eCheck Pre-Order Release Payment Approved: %s ending in %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:391 +msgid "Pre-Order Release Payment Failed: %s" +msgstr "Eeltellimuse väljastamise makse ebaõnnestus: %s" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:358 +msgid "Subscription Renewal: payment token is missing/invalid." +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:384 +msgid "%1$s - Subscription Renewal Order %2$s" +msgstr "" + +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error +#. message; e.g. Order Note: [Payment method] Payment Change failed [error] +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:516 +#, fuzzy +msgid "%1$s Payment Change Failed (%2$s)" +msgstr "%1$s: makse ebaõnnestus (%2$s)" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:671 +msgid "Via %s ending in %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:698 +msgid "Subscriptions" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:759 +msgid "N/A" +msgstr "-" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:858 +msgid "Payment Token" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:887 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:892 +msgid "%s is required." +msgstr "" + +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:180 +msgid "Unknown Error" +msgstr "Esines tundmatu viga" + +#: rest-api/Controllers/Settings.php:84 +msgid "Unique identifier for the resource." +msgstr "" + +#: rest-api/Controllers/Settings.php:119 +msgid "Sorry, you cannot list resources." +msgstr "" + +#. translators: Placeholder: %s - setting ID +#: rest-api/Controllers/Settings.php:168 +msgid "Setting %s does not exist" +msgstr "" + +#: rest-api/Controllers/Settings.php:191 +msgid "Sorry, you cannot edit this resource." +msgstr "" + +#: rest-api/Controllers/Settings.php:224 +msgid "Could not update setting: %s" +msgstr "" + +#: rest-api/Controllers/Settings.php:294 +msgid "Unique identifier of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:300 +msgid "The type of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:307 +msgid "The name of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:313 +msgid "The description of the setting. It may or may not be used for display." +msgstr "" + +#: rest-api/Controllers/Settings.php:319 +msgid "Whether the setting stores an array of values or a single value." +msgstr "" + +#: rest-api/Controllers/Settings.php:325 +msgid "A list of valid options, used for validation before storing the value." +msgstr "" + +#: rest-api/Controllers/Settings.php:331 +msgid "Optional default value for the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:337 +msgid "The value of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:342 +msgid "" +"Optional object that defines how the user will interact with and update the " +"setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:346 +msgid "The type of the control." +msgstr "" + +#: rest-api/Controllers/Settings.php:353 +msgid "The name of the control. Inherits the setting's name." +msgstr "" + +#: rest-api/Controllers/Settings.php:359 +msgid "The description of the control. Inherits the setting's description." +msgstr "" + +#: rest-api/Controllers/Settings.php:365 +msgid "" +"A list of key/value pairs defining the display value of each setting option. " +"The keys should match the options defined in the base setting for validation." +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:659 +msgid "Job data key \"%s\" not set" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:663 +msgid "Job data key \"%s\" is not an array" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:899 +msgid "Every %d Minutes" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1063 +msgid "Background Processing Test" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1064 +#, fuzzy +msgid "Run Test" +msgstr "test" + +#: utilities/class-sv-wp-background-job-handler.php:1065 +msgid "" +"This tool will test whether your server is capable of processing background " +"jobs." +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1083 +msgid "Success! You should be able to process background jobs." +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1086 +msgid "" +"Could not connect. Please ask your hosting company to ensure your server has " +"loopback connections enabled." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:395 +msgctxt "enhanced select" +msgid "No matches found" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:396 +msgctxt "enhanced select" +msgid "Loading failed" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:397 +msgctxt "enhanced select" +msgid "Please enter 1 or more characters" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:398 +msgctxt "enhanced select" +msgid "Please enter %qty% or more characters" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:399 +msgctxt "enhanced select" +msgid "Please delete 1 character" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:400 +msgctxt "enhanced select" +msgid "Please delete %qty% characters" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:401 +msgctxt "enhanced select" +msgid "You can only select 1 item" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:402 +msgctxt "enhanced select" +msgid "You can only select %qty% items" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:403 +msgctxt "enhanced select" +msgid "Loading more results…" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:404 +msgctxt "enhanced select" +msgid "Searching…" +msgstr "" + +#: class-sv-wc-helper.php:426 +msgctxt "coordinating conjunction for a list of items: a, b, and c" +msgid "and" +msgstr "" + +#: class-sv-wc-plugin.php:599 +msgctxt "noun" +msgid "Support" +msgstr "Kasutajatugi" + +#: class-sv-wc-plugin.php:604 +msgctxt "verb" +msgid "Review" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:749 +#: payment-gateway/class-sv-wc-payment-gateway.php:2688 +msgctxt "noun, software environment" +msgid "Test" +msgstr "test" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:750 +#: payment-gateway/class-sv-wc-payment-gateway.php:2689 +#: payment-gateway/class-sv-wc-payment-gateway.php:3170 +msgctxt "credit card transaction type" +msgid "Authorization" +msgstr "Autoriseerimine" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:750 +#: payment-gateway/class-sv-wc-payment-gateway.php:2689 +#: payment-gateway/class-sv-wc-payment-gateway.php:3169 +msgctxt "noun, credit card transaction type" +msgid "Charge" +msgstr "Makse" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:193 +msgctxt "payment method type" +msgid "Account" +msgstr "Konto" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:229 +#: payment-gateway/class-sv-wc-payment-gateway.php:3428 +msgctxt "credit card type" +msgid "Visa" +msgstr "Visa" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:233 +#: payment-gateway/class-sv-wc-payment-gateway.php:3429 +msgctxt "credit card type" +msgid "MasterCard" +msgstr "MasterCard" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:237 +#: payment-gateway/class-sv-wc-payment-gateway.php:3430 +msgctxt "credit card type" +msgid "American Express" +msgstr "American Express" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:241 +msgctxt "credit card type" +msgid "Diners Club" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:245 +#: payment-gateway/class-sv-wc-payment-gateway.php:3431 +msgctxt "credit card type" +msgid "Discover" +msgstr "Discover" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:249 +#: payment-gateway/class-sv-wc-payment-gateway.php:3433 +msgctxt "credit card type" +msgid "JCB" +msgstr "JCB" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:253 +msgctxt "credit card type" +msgid "CarteBleue" +msgstr "CarteBleue" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:257 +msgctxt "credit card type" +msgid "Maestro" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:261 +msgctxt "credit card type" +msgid "Laser" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3432 +msgctxt "credit card type" +msgid "Diners" +msgstr "Diners" + +#. translators: http:www.investopedia.com/terms/c/checkingaccount.asp +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:478 +msgctxt "account type" +msgid "Checking" +msgstr "Tšekikonto" + +#. translators: http:www.investopedia.com/terms/s/savingsaccount.asp +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:480 +msgctxt "account type" +msgid "Savings" +msgstr "Hoiuarve" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2465 +msgctxt "hash before order number" +msgid "#" +msgstr "#" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:753 +msgctxt "hash before order number" +msgid "#%s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3198 +msgctxt "" +"coordinating conjunction for a list of order statuses: on-hold, processing, " +"or completed" +msgid "or" +msgstr "" + +#. translators: https:www.skyverge.com/for-translators-environments/ +#: payment-gateway/class-sv-wc-payment-gateway.php:4003 +msgctxt "software environment" +msgid "Production" +msgstr "Töö/avalik" + +#~ msgid "My Payment Methods" +#~ msgstr "Minu maksevahendid." + +#~ msgid "Add New Payment Method" +#~ msgstr "Lisa uus maksevahend" + +#~ msgid "Method" +#~ msgstr "Maksevahend" + +#~ msgid "Expires" +#~ msgstr "Aegub" + +#~ msgid "Credit/Debit Cards" +#~ msgstr "Deebet- ja krediitkaardid" + +#~ msgid "Bank Accounts" +#~ msgstr "Pangakontod" + +#~ msgid "Delete" +#~ msgstr "Kustuta" + +#~ msgid "Error removing payment method" +#~ msgstr "Viga maksevahendi eemaldamisel" + +#~ msgid "Payment method deleted." +#~ msgstr "Maksevahend kustutatud." + +#, fuzzy +#~ msgid "Pay with" +#~ msgstr "Maksa" + +#~ msgid "%1$s Capture Failed: %2$s - %3$s" +#~ msgstr "%1$s: tasumine ebaõnnestus: %2$s - %3$s" + +#~ msgid "(check number %s)" +#~ msgstr "(tšeki number %s)" + +#~ msgid "Make Default" +#~ msgstr "Määra vaikimisi valikuks" + +#~ msgid "ending in %s" +#~ msgstr "lõpeb numbritega %s" + +#~ msgid "Default payment method updated." +#~ msgstr "Vaikimisi maksevahend muudetud." + +#~ msgid "Select which card types you accept." +#~ msgstr "Vali, millist tüüpi kaarte soovid vastu võtta." + +#~ msgid "" +#~ "The following plugins are inactive because they require a newer version " +#~ "to function properly:" +#~ msgstr "" +#~ "Järgnevad pluginad ei ole aktiivsed ja vajavad toimimiseks uuendamist:" + +#~ msgid "" +#~ "The following plugin is inactive because it requires a newer version to " +#~ "function properly:" +#~ msgstr "Järgnev plugin ei ole aktiivne ja vajab toimimiseks uuendamist:" + +#~ msgid "" +#~ "To reactivate these plugins, please %1$supdate now (recommended)%2$s " +#~ "%3$sor%4$s %5$sdeactivate the following%6$s:" +#~ msgstr "" +#~ "Et neid pluginaid taas sisse lülitada, %1$suuenda palun kohe " +#~ "(soovitatud)%2$s %3$svõi%4$s %5$slülita järgnevad välja%6$s:" + +#~ msgid "" +#~ "To reactivate this plugin, please %1$supdate now (recommended)%2$s " +#~ "%3$sor%4$s %5$sdeactivate the following%6$s:" +#~ msgstr "" +#~ "Et see plugin taas sisse lülitada, %1$suuenda palun kohe (soovitatud)%2$s " +#~ "%3$svõi%4$s %5$slülita järgnevad välja%6$s:" + +#~ msgid "%s Customer Details" +#~ msgstr "%s: kliendi andmed" + +#~ msgid "Customer ID (%s)" +#~ msgstr "Kliendi ID (%s)" + +#~ msgid "" +#~ "The gateway customer ID for the user in the %s environment. Only edit " +#~ "this if necessary." +#~ msgstr "" +#~ "Kasutajale makseviisi poolt määratud kliendi tunnus %s keskkonnas. Muuda " +#~ "seda ainult siis, kui tõesti vajalik." + +#~ msgid "This customer has no saved payment tokens" +#~ msgstr "Sel kliendil ei ole salvestatud maksevahendeid" + +#~ msgid "Default card" +#~ msgstr "Vaikimisi kaart" + +#~ msgid "Add a Payment Token" +#~ msgstr "Lisa maksevahend" + +#~ msgid "Token" +#~ msgstr "Vahend" + +#~ msgid "%s Subscription Renewal Approved" +#~ msgstr "Korduvtellimus summas %s uuendus kinnitatud" + +#~ msgid "Subscription Renewal: Payment Token or User ID is missing/invalid." +#~ msgstr "" +#~ "Korduvtellimuse uuendus: maksevahend või kasutajatunnus on puudu või " +#~ "vigane." + +#~ msgid "" +#~ "%1$s %2$s Subscription Renewal Payment Approved: %3$s ending in %4$s " +#~ "(expires %5$s)" +#~ msgstr "" +#~ "%1$s: %2$s korduvtellimuse uuendamise makse kinnitatud: %3$s lõpeb " +#~ "numbritega %4$s (aegub %5$s)" + +#~ msgid "" +#~ "%1$s Check Subscription Renewal Payment Approved: %2$s account ending in " +#~ "%3$s" +#~ msgstr "" +#~ "%1$s: tšekiga tasutav korduvtellimuse uuendamise makse kinnitatud: %2$s " +#~ "konto, lõpeb numbritega %3$s" + +#~ msgid "Via %1$s ending in %2$s" +#~ msgstr "%1$s, lõpeb numbritega %2$s" + +#~ msgid "%1$s Pre-Order Tokenization attempt failed (%2$s)" +#~ msgstr "" +#~ "%1$s: eeltellimuse maksevahendi salvestamise katse ebaõnnestus (%2$s)" + +#~ msgid "%1$s - Pre-Order Release Payment for Order %2$s" +#~ msgstr "%1$s - Eeltellimuse väljastamise makse tellimuse %2$s eest" + +#~ msgid "" +#~ "%1$s %2$s Pre-Order Release Payment Approved: %3$s ending in %4$s " +#~ "(expires %5$s)" +#~ msgstr "" +#~ "%1$s: %2$s eeltellimuse väljastamise makse vastu kinnitatud: %3$s lõpeb " +#~ "numbritega %4$s (aegub %5$s)" + +#~ msgid "%1$s eCheck Pre-Order Release Payment Approved: %2$s ending in %3$s" +#~ msgstr "" +#~ "%1$s: e-tšeki eeltellimuse väljastamise makse kinnitatud: %2$s lõpeb " +#~ "numbritega %3$s" + +#~ msgid "IPN processing error: %s duplicate transaction received" +#~ msgstr "IPN töötlemise viga: %s duplikaattehing" + +#~ msgid "%1$s %2$s Transaction Approved: %3$s ending in %4$s" +#~ msgstr "%1$s: %2$s tehing kinnitatud: %3$s lõpeb numbritega %4$s" + +#~ msgctxt "Supports capture charge" +#~ msgid "Capture Charge" +#~ msgstr "Makse " diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework.pot b/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework.pot new file mode 100644 index 0000000..5237524 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/i18n/languages/woocommerce-plugin-framework.pot @@ -0,0 +1,2034 @@ +# Copyright (C) 2023 +# This file is distributed under the same license as the package. +msgid "" +msgstr "" +"Project-Id-Version: WooCommerce Plugin Framework 5.11.4\n" +"Report-Msgid-Bugs-To: https://support.woocommerce.com/hc/\n" +"POT-Creation-Date: 2023-06-05 02:06:50+00:00\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"PO-Revision-Date: 2023-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" + +#: Lifecycle.php:394 +msgid "Awesome" +msgstr "" + +#: Lifecycle.php:395 +msgid "Fantastic" +msgstr "" + +#: Lifecycle.php:396 +msgid "Cowabunga" +msgstr "" + +#: Lifecycle.php:397 +msgid "Congratulations" +msgstr "" + +#: Lifecycle.php:398 +msgid "Hot dog" +msgstr "" + +#: Lifecycle.php:405 +#. translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - +#. tag, %4$s - tag, %5$s - tag +msgid "" +"Are you having a great experience with %1$s so far? Please consider " +"%2$sleaving a review%3$s! If things aren't going quite as expected, we're " +"happy to help -- please %4$sreach out to our support team%5$s." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:182 +msgid "" +"Thanks for installing %1$s! To get started, take a minute to %2$sread the " +"documentation%3$s :)" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:210 +msgid "" +"Thanks for installing %1$s! To get started, take a minute to complete these " +"%2$squick and easy setup steps%3$s :)" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:235 +msgid "Setup" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:303 +#. translators: Placeholders: %s - plugin name +msgid "%s › Setup" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:350 +msgid "Oops! An error occurred, please try again." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:488 +msgid "Ready!" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:581 +#. translators: Placeholder: %s - plugin name +msgid "Welcome to %s!" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:594 +msgid "" +"This quick setup wizard will help you configure the basic settings and get " +"you started." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:608 +msgid "%s is ready!" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:660 +msgid "Next step" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:686 +msgid "You can also:" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:730 +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:760 +msgid "View the Docs" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:731 +msgid "See more setup options" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:732 +msgid "Learn more about customizing the plugin" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:756 +msgid "Review Your Settings" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:764 +msgid "Leave a Review" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:788 +msgid "Continue" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:948 +msgid "Return to the WordPress Dashboard" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:950 +msgid "Not right now" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:952 +msgid "Skip this step" +msgstr "" + +#: class-sv-wc-framework-bootstrap.php:268 +msgid "" +"The following plugin is disabled because it is out of date and incompatible " +"with newer plugins on your site:" +msgid_plural "" +"The following plugins are disabled because they are out of date and " +"incompatible with newer plugins on your site:" +msgstr[0] "" +msgstr[1] "" + +#: class-sv-wc-framework-bootstrap.php:282 +msgid "" +"To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s " +"%5$sdeactivate%6$s the above plugin, or %7$sdeactivate the following%8$s:" +msgid_plural "" +"To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s " +"%5$sdeactivate%6$s the above plugins, or %7$sdeactivate the following%8$s:" +msgstr[0] "" +msgstr[1] "" + +#: class-sv-wc-framework-bootstrap.php:303 +msgid "" +"The following plugins are inactive because they require a newer version of " +"WooCommerce:" +msgstr "" + +#: class-sv-wc-framework-bootstrap.php:303 +msgid "" +"The following plugin is inactive because it requires a newer version of " +"WooCommerce:" +msgstr "" + +#: class-sv-wc-framework-bootstrap.php:308 +#. translators: Placeholders: %1$s - plugin name, %2$s - WooCommerce version +#. number +msgid "%1$s requires WooCommerce %2$s or newer" +msgstr "" + +#: class-sv-wc-framework-bootstrap.php:312 +#. translators: Placeholders: %1$s - tag, %2$s - tag +msgid "Please %1$supdate WooCommerce%2$s" +msgstr "" + +#: class-sv-wc-plugin-compatibility.php:217 +msgid "WooCommerce" +msgstr "" + +#: class-sv-wc-plugin-dependencies.php:156 +#. translators: Placeholders: %1$s - plugin name, %2$s - a PHP +#. extension/comma-separated list of PHP extensions +msgid "" +"%1$s requires the %2$s PHP extension to function. Contact your host or " +"server administrator to install and configure the missing extension." +msgid_plural "" +"%1$s requires the following PHP extensions to function: %2$s. Contact your " +"host or server administrator to install and configure the missing " +"extensions." +msgstr[0] "" +msgstr[1] "" + +#: class-sv-wc-plugin-dependencies.php:184 +#. translators: Placeholders: %1$s - plugin name, %2$s - a PHP +#. function/comma-separated list of PHP functions +msgid "" +"%1$s requires the %2$s PHP function to exist. Contact your host or server " +"administrator to install and configure the missing function." +msgid_plural "" +"%1$s requires the following PHP functions to exist: %2$s. Contact your " +"host or server administrator to install and configure the missing functions." +msgstr[0] "" +msgstr[1] "" + +#: class-sv-wc-plugin-dependencies.php:214 +#. translators: Placeholders: %s - plugin name +msgid "" +"%s may behave unexpectedly because the following PHP configuration settings " +"are required:" +msgstr "" + +#: class-sv-wc-plugin-dependencies.php:228 +msgid "%s or higher" +msgstr "" + +#: class-sv-wc-plugin-dependencies.php:238 +msgid "" +"Please contact your hosting provider or server administrator to configure " +"these settings." +msgstr "" + +#: class-sv-wc-plugin-dependencies.php:260 +#. translators: Placeholders: %1$s - , %2$s - +msgid "" +"Hey there! We've noticed that your server is running %1$san outdated " +"version of PHP%2$s, which is the programming language that WooCommerce and " +"its extensions are built on.\n" +"\t\t\t\t\tThe PHP version that is currently used for your site is no longer " +"maintained, nor %1$sreceives security updates%2$s; newer versions are " +"faster and more secure.\n" +"\t\t\t\t\tAs a result, %3$s no longer supports this version and you should " +"upgrade PHP as soon as possible.\n" +"\t\t\t\t\tYour hosting provider can do this for you. %4$sHere are some " +"resources to help you upgrade%5$s and to explain PHP versions further." +msgstr "" + +#: class-sv-wc-plugin.php:310 +#. translators: Placeholders: %s - plugin name +msgid "You cannot clone instances of %s." +msgstr "" + +#: class-sv-wc-plugin.php:321 +#. translators: Placeholders: %s - plugin name +msgid "You cannot unserialize instances of %s." +msgstr "" + +#: class-sv-wc-plugin.php:594 +#. translators: Docs as in Documentation +msgid "Docs" +msgstr "" + +#: class-sv-wc-plugin.php:709 +msgid "%1$s - A minimum of %2$s is required." +msgstr "" + +#: class-sv-wc-plugin.php:718 +msgid "Set as %1$s - %2$s is required." +msgstr "" + +#: class-sv-wc-plugin.php:1011 +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:876 +msgid "Configure" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:137 +#: payment-gateway/External_Checkout/Admin.php:147 +msgid "Processing Gateway" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:287 +msgid "Single products" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:288 +msgid "Cart" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:289 +msgid "Checkout" +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:330 +#. translators: Placeholder: %s - external checkout label +msgid "%s is disabled." +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:394 +#. translators: Placeholders: %1$s - plugin name, %2$s - a +#. currency/comma-separated list of currencies, %3$s - tag, %4$s - +#. tag, %5$s - external checkout label +msgid "" +"Accepts payment in %1$s only. %2$sConfigure%3$s WooCommerce to accept %1$s " +"to enable %4$s." +msgid_plural "" +"Accepts payment in one of %1$s only. %2$sConfigure%3$s WooCommerce to " +"accept one of %1$s to enable %4$s." +msgstr[0] "" +msgstr[1] "" + +#: payment-gateway/External_Checkout/Admin.php:436 +msgid "" +"%4$s%1$s Notice!%5$s Your store %2$scalculates taxes%3$s based on the " +"shipping address, but %1$s %4$sdoes not%5$s share customer shipping " +"information with your store for orders with only virtual products. These " +"orders will have their taxes calculated based on the shop address instead." +msgstr "" + +#: payment-gateway/External_Checkout/Admin.php:470 +msgid "" +"%4$s%1$s Notice!%5$s Your store %2$scalculates taxes%3$s based on the " +"billing address, but %1$s %4$sdoes not%5$s share the customer billing " +"address with your store before payment. These orders will have their taxes " +"calculated based on the shipping address (or shop address, for orders with " +"only virtual products)." +msgstr "" + +#: payment-gateway/External_Checkout/Frontend.php:259 +msgid "or" +msgstr "" + +#: payment-gateway/External_Checkout/Frontend.php:293 +msgid "By submitting your payment, you agree to our %1$sterms and conditions%2$s." +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:71 +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:87 +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:66 +msgid "Google Pay" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:93 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:93 +#: payment-gateway/class-sv-wc-payment-gateway.php:1262 +msgid "Enable / Disable" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:94 +msgid "Accept Google Pay" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:101 +msgid "Allow Google Pay on" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:111 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:111 +msgid "Button Style" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:114 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:114 +msgid "Black" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:115 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:115 +msgid "White" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:148 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:150 +#: payment-gateway/class-sv-wc-payment-gateway.php:1440 +msgid "Connection Settings" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:157 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:188 +msgid "Test Mode" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Admin.php:158 +msgid "" +"Enable to test Google Pay functionality throughout your sites without " +"processing real payments." +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Frontend.php:130 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:141 +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:99 +msgid "An error occurred, please try again or try an alternate form of payment" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:255 +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:380 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:539 +msgid "Subtotal" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:390 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:549 +msgid "Discount" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:400 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:559 +msgid "Shipping" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:410 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:569 +msgid "Fees" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:420 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:579 +msgid "Taxes" +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:463 +msgid "Google Pay payment authorized." +msgstr "" + +#: payment-gateway/External_Checkout/Google_Pay/Google_Pay.php:538 +msgid "Google Pay payment failed. %s" +msgstr "" + +#: payment-gateway/External_Checkout/Orders.php:140 +#: payment-gateway/External_Checkout/Orders.php:153 +#: payment-gateway/External_Checkout/Orders.php:157 +msgid "Error %d: Unable to create order. Please try again." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:71 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:87 +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:65 +msgid "Apple Pay" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:94 +msgid "Accept Apple Pay" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:101 +msgid "Allow Apple Pay on" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:116 +msgid "White with outline" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:159 +msgid "Apple Merchant ID" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:163 +msgid "This is found in your %1$sApple developer account%2$s" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:173 +msgid "Certificate Path" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:178 +#. translators: Placeholders: %s - the server's web root path +msgid "For reference, your current web root path is: %s" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:189 +msgid "" +"Enable to test Apple Pay functionality throughout your sites without " +"processing real payments." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:228 +msgid "Your site must be served over HTTPS with a valid SSL certificate." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:238 +msgid "" +"Your %1$sMerchant Identity Certificate%2$s cannot be found. Please check " +"your path configuration." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:176 +msgid "Buy with" +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:152 +msgid "Apple Pay payment authorized." +msgstr "" + +#: payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:186 +msgid "Apple Pay payment failed. %s" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:179 +msgid "" +"There was a problem processing your order and it is being placed on hold " +"for review. Please contact us to complete the transaction." +msgstr "" + +#: payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:217 +#: payment-gateway/class-sv-wc-payment-gateway.php:2898 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:521 +msgid "An error occurred, please try again or try an alternate form of payment." +msgstr "" + +#: payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:320 +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:449 +#. translators: Placeholders: %s - a WooCommerce order ID +msgid "Could not find order %s" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:152 +#: payment-gateway/class-sv-wc-payment-gateway.php:2487 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:172 +#. translators: Placeholders: %1$s - status code, %2$s - status message +#. translators: Placeholders: %1$s - payment request response status code, %2$s +#. - payment request response status message +msgid "Status code %1$s: %2$s" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:155 +#: payment-gateway/class-sv-wc-payment-gateway.php:2490 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:175 +#. translators: Placeholders: %s - status code +#. translators: Placeholders: %s - payment request response status code +msgid "Status code: %s" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:158 +#: payment-gateway/class-sv-wc-payment-gateway.php:2493 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:178 +#. translators: Placeholders; %s - status message +#. translators: Placeholders: %s - payment request response status message +msgid "Status message: %s" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:163 +#: payment-gateway/class-sv-wc-payment-gateway.php:2498 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:185 +msgid "Transaction ID %s" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:204 +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:513 +#. translators: Placeholders: %s - payment gateway title (such as +#. Authorize.net, Braintree, etc) +msgid "%s duplicate transaction received" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:207 +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:516 +msgid "Order %s is already paid for." +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:267 +#: payment-gateway/class-sv-wc-payment-gateway.php:2834 +msgid "" +"Your order has been received and is being reviewed. Thank you for your " +"business." +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:274 +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:864 +#: payment-gateway/class-sv-wc-payment-gateway.php:1865 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:370 +#. translators: This is a message describing that the transaction in question +#. only performed a credit card authorization and did not capture any funds. +msgid "Authorization only transaction" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:364 +#. translators: Placeholders: %s - payment gateway title +msgid "%s Transaction Held for Review" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:435 +#. translators: Placeholders: %s - payment gateway title +msgid "%s Payment Failed" +msgstr "" + +#: payment-gateway/Handlers/Abstract_Payment_Handler.php:462 +#. translators: Placeholders: %s - payment gateway title +msgid "%s Transaction Cancelled" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:158 +msgid "Order cannot be captured" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:163 +msgid "Transaction authorization has expired" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:168 +msgid "Transaction has already been fully captured" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:173 +msgid "Transaction cannot be captured" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:189 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - transaction amount. Definitions: +#. Capture, as in capture funds from a credit card. +msgid "%1$s Capture of %2$s Approved" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:198 +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:683 +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:768 +#: payment-gateway/class-sv-wc-payment-gateway.php:2166 +#: payment-gateway/class-sv-wc-payment-gateway.php:2399 +#: payment-gateway/class-sv-wc-payment-gateway.php:2715 +#: payment-gateway/class-sv-wc-payment-gateway.php:2760 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:353 +#. translators: Placeholders: %s - transaction ID +msgid "(Transaction ID %s)" +msgstr "" + +#: payment-gateway/Handlers/Capture.php:229 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - failure message. Definitions: +#. "capture" as in capturing funds from a credit card. +msgid "%1$s Capture Failed: %2$s" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:130 +msgid "Are you sure you wish to process this capture? The action cannot be undone." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:133 +msgid "" +"Something went wrong, and the capture could no be completed. Please try " +"again." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:178 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:267 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:330 +#. translators: verb, as in "Capture credit card charge". Used when an +#. amount has been pre-authorized before, but funds have not yet been captured +#. (taken) from the card. Capturing the charge will take the money from the +#. credit card and put it in the merchant's pockets. +msgid "Capture Charge" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:320 +msgid "This charge has been fully captured." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:322 +msgid "This charge can no longer be captured." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:324 +msgid "This charge cannot be captured." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:91 +msgid "Are you sure you want to remove this token?" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:101 +msgid "Invalid token data" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:105 +msgid "An error occurred. Please try again." +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:491 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:305 +msgid "(%s)" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:521 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:900 +msgid "Default" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:557 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:590 +msgid "Token ID" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:562 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:300 +msgid "Card Type" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:567 +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:603 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:192 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:298 +msgid "Last Four" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:574 +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:362 +msgid "Expiration (MM/YY)" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:595 +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:470 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:299 +#. translators: e-check account type, HTML form field label +msgid "Account Type" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:598 +msgid "Checking" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:599 +msgid "Savings" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:700 +msgid "Refresh" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:702 +msgid "Add New" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:705 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:297 +msgid "Save" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:728 +msgid "Remove" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:224 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:209 +msgid "%s Payment Tokens" +msgstr "" + +#: payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:302 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:862 +msgid "Customer ID" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:32 +msgid "This section contains configuration settings for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:53 +#: payment-gateway/class-sv-wc-payment-gateway.php:1389 +#. translators: environment as in a software environment (test/production) +msgid "Environment" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:54 +msgid "The transaction environment for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:61 +msgid "Tokenization Enabled" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:62 +msgid "Displays whether or not tokenization is enabled for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:75 +#: payment-gateway/class-sv-wc-payment-gateway.php:1316 +msgid "Debug Mode" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:76 +msgid "Displays whether or not debug logging is enabled for this gateway." +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:79 +msgid "Display at Checkout & Log" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:81 +msgid "Display at Checkout" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:83 +#: payment-gateway/class-sv-wc-payment-gateway.php:1324 +msgid "Save to Log" +msgstr "" + +#: payment-gateway/admin/views/html-admin-gateway-status.php:85 +#: payment-gateway/class-sv-wc-payment-gateway.php:1322 +msgid "Off" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:30 +msgid "Authorization total" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:34 +msgid "Amount already captured" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:40 +msgid "Remaining order total" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:46 +msgid "Capture amount" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:53 +msgid "Comment (optional):" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:65 +msgid "Capture %s" +msgstr "" + +#: payment-gateway/admin/views/html-order-partial-capture.php:66 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:608 +msgid "Cancel" +msgstr "" + +#: payment-gateway/admin/views/html-user-payment-token-editor-token.php:57 +msgid "-- Select an option --" +msgstr "" + +#: payment-gateway/admin/views/html-user-payment-token-editor.php:59 +msgid "No saved payment tokens" +msgstr "" + +#: payment-gateway/admin/views/html-user-profile-field-customer-id.php:30 +msgid "The gateway customer ID for the user. Only edit this if necessary." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:100 +msgid "" +"We cannot process your order with the payment information that you " +"provided. Please use a different payment account or an alternate payment " +"method." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:101 +msgid "" +"This order is being placed on hold for review. Please contact us to " +"complete the transaction." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:106 +msgid "" +"This order is being placed on hold for review due to an incorrect card " +"verification number. You may contact the store to complete the transaction." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:107 +msgid "The card verification number is invalid, please try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:108 +msgid "Please enter your card verification number and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:111 +msgid "" +"That card type is not accepted, please use an alternate card or other form " +"of payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:112 +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:116 +msgid "" +"The card type is invalid or does not correlate with the credit card number. " +" Please try again or use an alternate card or other form of payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:113 +msgid "Please select the card type and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:117 +msgid "The card number is invalid, please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:118 +msgid "Please enter your card number and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:121 +msgid "The card expiration date is invalid, please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:122 +msgid "The card expiration month is invalid, please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:123 +msgid "The card expiration year is invalid, please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:124 +msgid "Please enter your card expiration date and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:127 +msgid "The bank routing number is invalid, please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:128 +msgid "The bank account number is invalid, please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:131 +msgid "" +"The provided card is expired, please use an alternate card or other form of " +"payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:132 +msgid "" +"The provided card was declined, please use an alternate card or other form " +"of payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:133 +msgid "" +"Insufficient funds in account, please use an alternate card or other form " +"of payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:134 +msgid "" +"The card is inactivate or not authorized for card-not-present transactions, " +"please use an alternate card or other form of payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:135 +msgid "" +"The credit limit for the card has been reached, please use an alternate " +"card or other form of payment." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:136 +msgid "The card verification number does not match. Please re-enter and try again." +msgstr "" + +#: payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:137 +msgid "" +"The provided address does not match the billing address for cardholder. " +"Please verify the address and try again." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:61 +msgid "" +"Payment error, please try another payment method or contact us to complete " +"your transaction." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:161 +#: payment-gateway/class-sv-wc-payment-gateway.php:503 +msgid "Card expiration date is invalid" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:185 +#: payment-gateway/class-sv-wc-payment-gateway.php:496 +msgid "Card number is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:191 +#: payment-gateway/class-sv-wc-payment-gateway.php:499 +msgid "Card number is invalid (wrong length)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:196 +#: payment-gateway/class-sv-wc-payment-gateway.php:498 +msgid "Card number is invalid (only digits allowed)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:201 +#: payment-gateway/class-sv-wc-payment-gateway.php:497 +msgid "Card number is invalid" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:228 +#: payment-gateway/class-sv-wc-payment-gateway.php:501 +msgid "Card security code is invalid (only digits are allowed)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:234 +#: payment-gateway/class-sv-wc-payment-gateway.php:502 +msgid "Card security code is invalid (must be 3 or 4 digits)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:240 +#: payment-gateway/class-sv-wc-payment-gateway.php:500 +msgid "Card security code is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:267 +#: payment-gateway/class-sv-wc-payment-gateway.php:512 +msgid "Routing Number is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:274 +#: payment-gateway/class-sv-wc-payment-gateway.php:513 +msgid "Routing Number is invalid (only digits are allowed)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:280 +#: payment-gateway/class-sv-wc-payment-gateway.php:514 +msgid "Routing number is invalid (must be 9 digits)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:289 +#: payment-gateway/class-sv-wc-payment-gateway.php:509 +msgid "Account Number is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:296 +#: payment-gateway/class-sv-wc-payment-gateway.php:510 +msgid "Account Number is invalid (only digits are allowed)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:302 +#: payment-gateway/class-sv-wc-payment-gateway.php:511 +msgid "Account number is invalid (must be between 5 and 17 digits)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:309 +#: payment-gateway/class-sv-wc-payment-gateway.php:508 +msgid "Drivers license number is invalid" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:315 +#: payment-gateway/class-sv-wc-payment-gateway.php:504 +msgid "Check Number is invalid (only digits are allowed)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:494 +msgid "Unknown error" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:503 +msgid "Payment method address could not be updated. %s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:673 +#: payment-gateway/class-sv-wc-payment-gateway.php:2750 +#. translators: Placeholders: %1$s - payment method title, %2$s - payment +#. account type (savings/checking) (may or may not be available), %3$s - last +#. four digits of the account +msgid "%1$s Check Transaction Approved: %2$s account ending in %3$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:678 +#: payment-gateway/class-sv-wc-payment-gateway.php:2755 +#. translators: Placeholders: %s - check number +msgid "Check number %s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:747 +#. translators: Placeholders: %1$s - payment method title, %2$s - environment +#. ("Test"), %3$s - transaction type (authorization/charge), %4$s - card type +#. (mastercard, visa, ...), %5$s - last four digits of the card +msgid "%1$s %2$s %3$s Approved: %4$s ending in %5$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:760 +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:718 +#: payment-gateway/class-sv-wc-payment-gateway.php:2707 +#. translators: Placeholders: %s - expiry date +msgid "(expires %s)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:832 +#. translators: Placeholders: %s - failure message +msgid "Tokenization Request Failed: %s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:843 +#. translators: Placeholders: %1$s - payment method title, %2$s - failure +#. message +msgid "%1$s Tokenization Request Failed: %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:901 +#. translators: Placeholders: %s - failure message. Payment method as in a +#. specific credit card, e-check or bank account +msgid "Oops, adding your new payment method failed: %s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:946 +#. translators: Payment method as in a specific credit card. Placeholders: %1$s +#. - card type (visa, mastercard, ...), %2$s - last four digits of the card, +#. %3$s - card expiry date +msgid "Nice! New payment method added: %1$s ending in %2$s (expires %3$s)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:956 +#. translators: Payment method as in a specific e-check account. Placeholders: +#. %1$s - account type (checking/savings), %2$s - last four digits of the +#. account +msgid "Nice! New payment method added: %1$s account ending in %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:963 +#. translators: Payment method as in a specific credit card, e-check or bank +#. account +msgid "Nice! New payment method added." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:1086 +#. translators: Placeholders: %1$s - site title, %2$s - customer email. Payment +#. method as in a specific credit card, e-check or bank account +msgid "%1$s - Add Payment Method for %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:180 +msgid "PayPal" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:181 +msgid "Checking Account" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:182 +msgid "Savings Account" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:183 +msgid "Credit / Debit Card" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:184 +msgid "Bank Account" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:301 +msgid "Thank you for your order, please click the button below to pay." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:302 +msgid "Thank you for your order. We are now redirecting you to complete payment." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:303 +msgid "Pay Now" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:304 +msgid "Cancel Order" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:601 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:1114 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - payment method name (mastercard, bank +#. account, etc), %3$s - last four digits of the card/account, %4$s - +#. card/account expiry date +msgid "%1$s Payment Method Saved: %2$s ending in %3$s (expires %4$s)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:612 +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:1125 +#. translators: Placeholders: %1$s - payment gateway title (such as CyberSouce, +#. NETbilling, etc), %2$s - account type (checking/savings - may or may not be +#. available), %3$s - last four digits of the account +msgid "%1$s eCheck Payment Method Saved: %2$s account ending in %3$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:621 +#. translators: Placeholders: %s - payment gateway title (such as CyberSouce, +#. NETbilling, etc) +msgid "%s Payment Method Saved" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-hosted.php:630 +#. translators: Placeholders: %s - a failed tokenization API error +msgid "Tokenization failed. %s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:293 +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:607 +msgid "Edit" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:337 +#: payment-gateway/class-sv-wc-payment-gateway.php:1269 +msgid "Title" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:340 +msgid "Details" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:343 +msgid "Default?" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:609 +msgid "Oops, there was an error updating your payment method. Please try again." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:610 +msgid "Are you sure you want to delete this payment method?" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:697 +#. translators: Payment method as in a specific credit card, eCheck or bank +#. account +msgid "You do not have any saved payment methods." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:872 +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:200 +msgid "Nickname" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:1118 +msgid "Oops, you took too long, please try again." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:1129 +msgid "There was an error with your request, please try again." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:344 +msgid "Card Number" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:365 +msgid "MM / YY" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:384 +msgid "Card Security Code" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:387 +msgid "CSC" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:427 +msgid "Where do I find this?" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:433 +#. translators: e-check routing number, HTML form field label, +#. https:en.wikipedia.org/wiki/Routing_transit_number +msgid "Routing Number" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:452 +#. translators: e-check account number, HTML form field label +msgid "Account Number" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:518 +#. translators: Test mode refers to the current software environment +msgid "TEST MODE ENABLED" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:545 +msgid "Sample Check" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:620 +#. translators: Payment method as in a specific credit card, eCheck or bank +#. account +msgid "Manage Payment Methods" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:757 +msgid "Use a new card" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:757 +msgid "Use a new bank account" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:820 +#. translators: account as in customer's account on the eCommerce site +msgid "Securely Save to Account" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:954 +msgid "Payment Info" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:706 +#. translators: Placeholders: %1$s - plugin name, %2$s - tag, %3$s - +#. tag +msgid "" +"%1$s: WooCommerce is not being forced over SSL; your customers' payment " +"data may be at risk. %2$sVerify your site URLs here%3$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:723 +#. translators: Placeholders: %s - payment gateway name +msgid "" +"%s will soon require TLS 1.2 support to process transactions and your " +"server environment may need to be updated. Please contact your hosting " +"provider to confirm that your site can send and receive TLS 1.2 connections " +"and request they make any necessary updates." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:779 +#. translators: Placeholders: %1$s - plugin name, %2$s - a +#. currency/comma-separated list of currencies, %3$s - tag, %4$s - tag +msgid "" +"%1$s accepts payment in %2$s only. %3$sConfigure%4$s WooCommerce to accept " +"%2$s to enable this gateway for checkout." +msgid_plural "" +"%1$s accepts payment in one of %2$s only. %3$sConfigure%4$s WooCommerce to " +"accept one of %2$s to enable this gateway for checkout." +msgstr[0] "" +msgstr[1] "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:814 +#. translators: Placeholders: %1$s - payment gateway name, %2$s - opening +#. tag, %3$s - closing tag +msgid "" +"Heads up! %1$s is currently configured to log transaction data for " +"debugging purposes. If you are not experiencing any problems with payment " +"processing, we recommend %2$sturning off Debug Mode%3$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:865 +#. translators: Placeholders: %s - gateway name +msgid "%s is not configured" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:877 +msgid "Dismiss" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:914 +#. translators: Placeholders: %1$s - plugin name, %2$s - opening HTML link +#. tag, %3$s - closing HTML link tag +msgid "" +"Heads up! Apple Pay for %1$s requires WooCommerce version 3.2 or greater. " +"Please %2$supdate WooCommerce%3$s." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:938 +#. translators: Placeholders: %1$s - plugin name, %2$s - opening HTML link +#. tag, %3$s - closing HTML link tag +msgid "" +"Heads up! Google Pay for %1$s requires WooCommerce version 3.2 or greater. " +"Please %2$supdate WooCommerce%3$s." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:974 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - tag, %3$s - tag +msgid "" +"%1$s is inactive for subscription transactions. Please %2$senable " +"tokenization%3$s to activate %1$s for Subscriptions." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:992 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - tag, %3$s - tag +msgid "" +"%1$s is inactive for pre-order transactions. Please %2$senable " +"tokenization%3$s to activate %1$s for Pre-Orders." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:1029 +msgid "" +"You must enable tokenization for this gateway in order to support automatic " +"renewal payments with the WooCommerce Subscriptions extension." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-plugin.php:1030 +msgid "Inactive" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:115 +msgid "%s Customer ID" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:184 +msgid "Type" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:254 +msgid "Removed payment token \"%d\"" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-privacy.php:301 +msgid "Expiry Date" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:350 +msgid "you successfully processed a payment!" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:355 +msgid "you successfully processed a refund!" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:505 +msgid "Check Number is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:506 +msgid "Drivers license state is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:507 +msgid "Drivers license number is missing" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:720 +msgid "Continue to Payment" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:720 +msgid "Place order" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:752 +msgid "Thank you for your order." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1221 +msgid "Credit Card" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1223 +msgid "eCheck" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1241 +msgid "Pay securely using your credit card." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1243 +msgid "Pay securely using your checking account." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1263 +msgid "Enable this gateway" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1271 +msgid "Payment method title that the customer will see during checkout." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1276 +msgid "Description" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1278 +msgid "Payment method description that the customer will see during checkout." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1307 +msgid "Detailed Decline Messages" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1309 +msgid "" +"Check to enable detailed decline messages to the customer during checkout " +"when possible, rather than a generic decline message." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1319 +#. translators: Placeholders: %1$s - tag, %2$s - tag +msgid "" +"Show Detailed Error Messages and API requests/responses on the checkout " +"page and/or save them to the %1$sdebug log%2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1323 +msgid "Show on Checkout Page" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1326 +#. translators: show debugging information on both checkout page and in the log +msgid "Both" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1392 +msgid "Select the gateway environment to use for transactions." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1446 +msgid "Share connection settings" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1448 +msgid "Use connection/authentication settings from other gateway" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1451 +msgid "Disabled because the other gateway is using these settings" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1468 +msgid "Card Verification (CSC)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1469 +msgid "Display the Card Security Code (CV2) field on checkout" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1477 +msgid "Saved Card Verification" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1478 +msgid "Display the Card Security Code field when paying with a saved card" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1813 +#. translators: Placeholders: %1$s - site title, %2$s - order number +msgid "%1$s - Order %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:1947 +#. translators: Placeholders: %1$s - site title, %2$s - order number. +#. Definitions: Capture as in capture funds from a credit card. +msgid "%1$s - Capture for Order %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2090 +#. translators: Placeholders: %1$s - site title, %2$s - order number +msgid "%1$s - Refund for Order %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2157 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - a monetary amount +msgid "%1$s Refund in the amount of %2$s approved." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2187 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - error code, %3$s - error message +msgid "%1$s Refund Failed: %2$s - %3$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2195 +#. translators: Placeholders: %1$s - payment gateway title (such as +#. Authorize.net, Braintree, etc), %2$s - error message +msgid "%1$s Refund Failed: %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2216 +#. translators: Placeholders: %s - payment gateway title (such as +#. Authorize.net, Braintree, etc) +msgid "%s Order completely refunded." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2271 +msgid "" +"Oops, you cannot partially void this order. Please use the full order " +"amount." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2358 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error code, +#. %3$s - error message. Void as in to void an order. +msgid "%1$s Void Failed: %2$s - %3$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2366 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error +#. message. Void as in to void an order. +msgid "%1$s Void Failed: %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2390 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - a monetary +#. amount. Void as in to void an order. +msgid "%1$s Void in the amount of %2$s approved." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2686 +#. translators: Placeholders: %1$s - payment method title, %2$s - environment +#. ("Test"), %3$s - transaction type (authorization/charge) +msgid "%1$s %2$s %3$s Approved" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2696 +#. translators: Placeholders: %1$s - credit card type (MasterCard, Visa, +#. etc...), %2$s - last four digits of the card +msgid "%1$s ending in %2$s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2792 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - message +#. (probably reason for the transaction being held for review) +msgid "%1$s Transaction Held for Review (%2$s)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2881 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error +#. message; e.g. Order Note: [Payment method] Payment failed [error] +msgid "%1$s Payment Failed (%2$s)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2916 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - +#. message/error +msgid "%1$s Transaction Cancelled (%2$s)" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3164 +msgid "Transaction Type" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3166 +msgid "" +"Select how transactions should be processed. Charge submits all " +"transactions for settlement, Authorization simply authorizes the order " +"total for capture later." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3177 +msgid "Charge Virtual-Only Orders" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3179 +msgid "" +"If the order contains exclusively virtual items, enable this to immediately " +"charge, rather than authorize, the transaction." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3187 +msgid "Enable Partial Capture" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3189 +msgid "Allow orders to be partially captured multiple times." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3201 +msgid "Capture Paid Orders" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3204 +msgid "Automatically capture orders when they are changed to %s." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3205 +msgid "a paid status" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3395 +msgid "Accepted Card Logos" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3397 +msgid "" +"These are the card logos that are displayed to customers as accepted during " +"checkout." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3400 +#. translators: Placeholders: %1$s - tag, %2$s - tag +msgid "" +"This setting %1$sdoes not%2$s change which card types the gateway will " +"accept. Accepted cards are configured from your payment processor account." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3491 +#. translators: +#. http:www.cybersource.com/products/payment_security/payment_tokenization/ and +#. https:en.wikipedia.org/wiki/Tokenization_(data_security) +msgid "Tokenization" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3492 +msgid "Allow customers to securely save their payment details for future checkout." +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:4277 +#. translators: %1$s - gateway name, %2$s - tag, %3$s - tag, %4$s - +#. tag, %5$s - tag +msgid "" +"Heads up! %1$s is not fully configured and cannot accept payments. Please " +"%2$sreview the documentation%3$s and configure the %4$sgateway settings%5$s." +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:261 +msgid "Pre-Order Tokenization attempt failed (%s)" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:307 +msgid "%s - Pre-Order Release Payment for Order %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:311 +msgid "Payment token missing/invalid." +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:336 +msgid "%s %s Pre-Order Release Payment Approved: %s ending in %s (expires %s)" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:347 +msgid "%s eCheck Pre-Order Release Payment Approved: %s ending in %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:391 +msgid "Pre-Order Release Payment Failed: %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:358 +msgid "Subscription Renewal: payment token is missing/invalid." +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:384 +msgid "%1$s - Subscription Renewal Order %2$s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:516 +#. translators: Placeholders: %1$s - payment gateway title, %2$s - error +#. message; e.g. Order Note: [Payment method] Payment Change failed [error] +msgid "%1$s Payment Change Failed (%2$s)" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:671 +msgid "Via %s ending in %s" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:698 +msgid "Subscriptions" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:759 +msgid "N/A" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:858 +msgid "Payment Token" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:887 +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:892 +msgid "%s is required." +msgstr "" + +#: payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:180 +msgid "Unknown Error" +msgstr "" + +#: rest-api/Controllers/Settings.php:84 +msgid "Unique identifier for the resource." +msgstr "" + +#: rest-api/Controllers/Settings.php:119 +msgid "Sorry, you cannot list resources." +msgstr "" + +#: rest-api/Controllers/Settings.php:168 +#. translators: Placeholder: %s - setting ID +msgid "Setting %s does not exist" +msgstr "" + +#: rest-api/Controllers/Settings.php:191 +msgid "Sorry, you cannot edit this resource." +msgstr "" + +#: rest-api/Controllers/Settings.php:224 +msgid "Could not update setting: %s" +msgstr "" + +#: rest-api/Controllers/Settings.php:294 +msgid "Unique identifier of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:300 +msgid "The type of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:307 +msgid "The name of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:313 +msgid "The description of the setting. It may or may not be used for display." +msgstr "" + +#: rest-api/Controllers/Settings.php:319 +msgid "Whether the setting stores an array of values or a single value." +msgstr "" + +#: rest-api/Controllers/Settings.php:325 +msgid "A list of valid options, used for validation before storing the value." +msgstr "" + +#: rest-api/Controllers/Settings.php:331 +msgid "Optional default value for the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:337 +msgid "The value of the setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:342 +msgid "" +"Optional object that defines how the user will interact with and update the " +"setting." +msgstr "" + +#: rest-api/Controllers/Settings.php:346 +msgid "The type of the control." +msgstr "" + +#: rest-api/Controllers/Settings.php:353 +msgid "The name of the control. Inherits the setting's name." +msgstr "" + +#: rest-api/Controllers/Settings.php:359 +msgid "The description of the control. Inherits the setting's description." +msgstr "" + +#: rest-api/Controllers/Settings.php:365 +msgid "" +"A list of key/value pairs defining the display value of each setting " +"option. The keys should match the options defined in the base setting for " +"validation." +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:659 +msgid "Job data key \"%s\" not set" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:663 +msgid "Job data key \"%s\" is not an array" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:899 +msgid "Every %d Minutes" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1063 +msgid "Background Processing Test" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1064 +msgid "Run Test" +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1065 +msgid "" +"This tool will test whether your server is capable of processing background " +"jobs." +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1083 +msgid "Success! You should be able to process background jobs." +msgstr "" + +#: utilities/class-sv-wp-background-job-handler.php:1086 +msgid "" +"Could not connect. Please ask your hosting company to ensure your server " +"has loopback connections enabled." +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:395 +msgctxt "enhanced select" +msgid "No matches found" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:396 +msgctxt "enhanced select" +msgid "Loading failed" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:397 +msgctxt "enhanced select" +msgid "Please enter 1 or more characters" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:398 +msgctxt "enhanced select" +msgid "Please enter %qty% or more characters" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:399 +msgctxt "enhanced select" +msgid "Please delete 1 character" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:400 +msgctxt "enhanced select" +msgid "Please delete %qty% characters" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:401 +msgctxt "enhanced select" +msgid "You can only select 1 item" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:402 +msgctxt "enhanced select" +msgid "You can only select %qty% items" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:403 +msgctxt "enhanced select" +msgid "Loading more results…" +msgstr "" + +#: admin/abstract-sv-wc-plugin-admin-setup-wizard.php:404 +msgctxt "enhanced select" +msgid "Searching…" +msgstr "" + +#: class-sv-wc-helper.php:426 +msgctxt "coordinating conjunction for a list of items: a, b, and c" +msgid "and" +msgstr "" + +#: class-sv-wc-plugin.php:599 +msgctxt "noun" +msgid "Support" +msgstr "" + +#: class-sv-wc-plugin.php:604 +msgctxt "verb" +msgid "Review" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:749 +#: payment-gateway/class-sv-wc-payment-gateway.php:2688 +msgctxt "noun, software environment" +msgid "Test" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:750 +#: payment-gateway/class-sv-wc-payment-gateway.php:2689 +#: payment-gateway/class-sv-wc-payment-gateway.php:3170 +msgctxt "credit card transaction type" +msgid "Authorization" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-direct.php:750 +#: payment-gateway/class-sv-wc-payment-gateway.php:2689 +#: payment-gateway/class-sv-wc-payment-gateway.php:3169 +msgctxt "noun, credit card transaction type" +msgid "Charge" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:193 +msgctxt "payment method type" +msgid "Account" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:229 +#: payment-gateway/class-sv-wc-payment-gateway.php:3428 +msgctxt "credit card type" +msgid "Visa" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:233 +#: payment-gateway/class-sv-wc-payment-gateway.php:3429 +msgctxt "credit card type" +msgid "MasterCard" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:237 +#: payment-gateway/class-sv-wc-payment-gateway.php:3430 +msgctxt "credit card type" +msgid "American Express" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:241 +msgctxt "credit card type" +msgid "Diners Club" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:245 +#: payment-gateway/class-sv-wc-payment-gateway.php:3431 +msgctxt "credit card type" +msgid "Discover" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:249 +#: payment-gateway/class-sv-wc-payment-gateway.php:3433 +msgctxt "credit card type" +msgid "JCB" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:253 +msgctxt "credit card type" +msgid "CarteBleue" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:257 +msgctxt "credit card type" +msgid "Maestro" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-helper.php:261 +msgctxt "credit card type" +msgid "Laser" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3432 +msgctxt "credit card type" +msgid "Diners" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:478 +#. translators: http:www.investopedia.com/terms/c/checkingaccount.asp +msgctxt "account type" +msgid "Checking" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway-payment-form.php:480 +#. translators: http:www.investopedia.com/terms/s/savingsaccount.asp +msgctxt "account type" +msgid "Savings" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:2465 +msgctxt "hash before order number" +msgid "#" +msgstr "" + +#: payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:753 +msgctxt "hash before order number" +msgid "#%s" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:3198 +msgctxt "" +"coordinating conjunction for a list of order statuses: on-hold, processing, " +"or completed" +msgid "or" +msgstr "" + +#: payment-gateway/class-sv-wc-payment-gateway.php:4003 +#. translators: https:www.skyverge.com/for-translators-environments/ +msgctxt "software environment" +msgid "Production" +msgstr "" \ No newline at end of file diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/index.php b/vendor/skyverge/wc-plugin-framework/woocommerce/index.php new file mode 100644 index 0000000..129bbf3 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/index.php @@ -0,0 +1,29 @@ +settings = $settings; + $this->namespace = 'wc/v3'; + $this->rest_base = "{$settings->get_id()}/settings"; + } + + + /** + * Registers the API routes. + * + * @since 5.7.0 + */ + public function register_routes() { + + register_rest_route( + $this->namespace, "/{$this->rest_base}", [ + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'get_items' ], + 'permission_callback' => [ $this, 'get_items_permissions_check' ], + ], + 'schema' => [ $this, 'get_public_item_schema' ], + ] + ); + + register_rest_route( + $this->namespace, "/{$this->rest_base}/(?P[\w-]+)", [ + 'args' => [ + 'id' => [ + 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ), + 'type' => 'string', + ], + ], + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'get_item' ], + 'permission_callback' => [ $this, 'get_items_permissions_check' ], + ], + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'update_item' ], + 'permission_callback' => [ $this, 'update_item_permissions_check' ], + 'args' => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE ), + ], + 'schema' => [ $this, 'get_public_item_schema' ], + ] + ); + } + + + /** Read methods **************************************************************************************************/ + + + /** + * Checks whether the user has permissions to get settings. + * + * @since 5.7.0 + * + * @param \WP_REST_Request $request request object + * @return bool|\WP_Error + */ + public function get_items_permissions_check( $request ) { + + if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { + return new \WP_Error( 'wc_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-plugin-framework' ), [ 'status' => rest_authorization_required_code() ] ); + } + + return true; + } + + + /** + * Gets all registered settings. + * + * @since 5.7.0 + * + * @param \WP_REST_Request $request request object + * @return \WP_REST_Response|\WP_Error + */ + public function get_items( $request ) { + + $items = []; + + foreach ( $this->settings->get_settings() as $setting ) { + $items[] = $this->prepare_setting_item( $setting, $request ); + } + + return rest_ensure_response( $items ); + } + + + /** + * Gets a single setting. + * + * @since 5.7.0 + * + * @param \WP_REST_Request $request request object + * @return \WP_REST_Response|\WP_Error + */ + public function get_item( $request ) { + + $setting_id = $request->get_param( 'id' ); + + if ( $setting = $this->settings->get_setting( $setting_id ) ) { + + return rest_ensure_response( $this->prepare_setting_item( $setting, $request ) ); + + } else { + + return new \WP_Error( + 'wc_rest_setting_not_found', + sprintf( + /* translators: Placeholder: %s - setting ID */ + __( 'Setting %s does not exist', 'woocommerce-plugin-framework' ), + $setting_id + ), + [ 'status' => 404 ] + ); + } + } + + + /** Update methods ************************************************************************************************/ + + + /** + * Checks whether the user has permissions to update a setting. + * + * @since 5.7.0 + * + * @param \WP_REST_Request $request request object + * @return bool|\WP_Error + */ + public function update_item_permissions_check( $request ) { + + if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) { + return new \WP_Error( 'wc_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce-plugin-framework' ), [ 'status' => rest_authorization_required_code() ] ); + } + + return true; + } + + + /** + * Updates a single setting. + * + * @since 5.7.0 + * + * @param \WP_REST_Request $request request object + * @return WP_Error|WP_REST_Response + */ + public function update_item( $request ) { + + try { + + $setting_id = $request->get_param( 'id' ); + $value = $request->get_param( 'value' ); + + // throws an exception if the setting doesn't exist or the value is not valid + $this->settings->update_value( $setting_id, $value ); + + return rest_ensure_response( $this->prepare_setting_item( $this->settings->get_setting( $setting_id ), $request ) ); + + } catch ( \Exception $e ) { + + return new \WP_Error( + 'wc_rest_setting_could_not_update', + sprintf( + /* Placeholders: %s - error message */ + __( 'Could not update setting: %s', 'woocommerce-plugin-framework' ), + $e->getMessage() + ), + [ 'status' => $e->getCode() ?: 400 ] + ); + } + } + + + /** Utility methods ***********************************************************************************************/ + + + /** + * Prepares the item for the REST response. + * + * @since 5.7.0 + * + * @param Setting $setting a setting object + * @param \WP_REST_Request $request request object + * @return array + */ + public function prepare_setting_item( $setting, $request ) { + + if ( $setting instanceof Setting ) { + + $item = [ + 'id' => $setting->get_id(), + 'type' => $setting->get_type(), + 'name' => $setting->get_name(), + 'description' => $setting->get_description(), + 'is_multi' => $setting->is_is_multi(), + 'options' => $setting->get_options(), + 'default' => $setting->get_default(), + 'value' => $setting->get_value(), + 'control' => null, + ]; + + if ( $control = $setting->get_control() ) { + $item['control'] = [ + 'type' => $control->get_type(), + 'name' => $control->get_name(), + 'description' => $control->get_description(), + 'options' => $control->geT_options(), + ]; + } + + } else { + + $item = []; + } + + return $item; + } + + + /** + * Retrieves the item's schema, conforming to JSON Schema. + * + * @since 5.7.0 + * + * @return array + */ + public function get_item_schema() { + + $schema = [ + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => "{$this->settings->get_id()}_setting", + 'type' => 'object', + 'properties' => [ + 'id' => [ + 'description' => __( 'Unique identifier of the setting.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'type' => [ + 'description' => __( 'The type of the setting.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'enum' => $this->settings->get_setting_types(), + 'readonly' => true, + ], + 'name' => [ + 'description' => __( 'The name of the setting.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'description' => [ + 'description' => __( 'The description of the setting. It may or may not be used for display.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'is_multi' => [ + 'description' => __( 'Whether the setting stores an array of values or a single value.', 'woocommerce-plugin-framework' ), + 'type' => 'boolean', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'options' => [ + 'description' => __( 'A list of valid options, used for validation before storing the value.', 'woocommerce-plugin-framework' ), + 'type' => 'array', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'default' => [ + 'description' => __( 'Optional default value for the setting.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'value' => [ + 'description' => __( 'The value of the setting.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + ], + 'control' => [ + 'description' => __( 'Optional object that defines how the user will interact with and update the setting.', 'woocommerce-memberships' ), + 'type' => 'object', + 'properties' => [ + 'type' => [ + 'description' => __( 'The type of the control.', 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'enum' => $this->settings->get_control_types(), + 'readonly' => true, + ], + 'name' => [ + 'description' => __( "The name of the control. Inherits the setting's name.", 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'description' => [ + 'description' => __( "The description of the control. Inherits the setting's description.", 'woocommerce-plugin-framework' ), + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + 'options' => [ + 'description' => __( 'A list of key/value pairs defining the display value of each setting option. The keys should match the options defined in the base setting for validation.', 'woocommerce-plugin-framework' ), + 'type' => 'array', + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + ], + 'context' => [ 'view', 'edit' ], + 'readonly' => true, + ], + ], + ]; + + return $this->add_additional_fields_schema( $schema ); + } + + +} + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/rest-api/class-sv-wc-plugin-rest-api.php b/vendor/skyverge/wc-plugin-framework/woocommerce/rest-api/class-sv-wc-plugin-rest-api.php new file mode 100644 index 0000000..0f7c1f9 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/rest-api/class-sv-wc-plugin-rest-api.php @@ -0,0 +1,162 @@ +plugin = $plugin; + + $this->add_hooks(); + } + + + /** + * Adds the action and filter hooks. + * + * @since 5.2.0 + */ + protected function add_hooks() { + + // add plugin data to the system status + add_filter( 'woocommerce_rest_prepare_system_status', array( $this, 'add_system_status_data' ), 10, 3 ); + + // registers new WC REST API routes + add_action( 'rest_api_init', array( $this, 'register_routes' ) ); + } + + + /** + * Adds plugin data to the system status. + * + * @internal + * + * @since 5.2.0 + * + * @param \WP_REST_Response $response REST API response object + * @param array $system_status system status data + * @param \WP_REST_Request $request REST API request object + * @return \WP_REST_Response + */ + public function add_system_status_data( $response, $system_status, $request ) { + + $data = array( + 'is_payment_gateway' => $this->get_plugin() instanceof SV_WC_Payment_Gateway_Plugin, + 'lifecycle_events' => $this->get_plugin()->get_lifecycle_handler()->get_event_history(), + ); + + $data = array_merge( $data, $this->get_system_status_data() ); + + /** + * Filters the data added to the WooCommerce REST API System Status response. + * + * @since 5.2.0 + * + * @param array $data system status response data + * @param \WP_REST_Response $response REST API response object + * @param \WP_REST_Request $request REST API request object + */ + $data = apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_rest_api_system_status_data', $data, $response, $request ); + + $response->data[ 'wc_' . $this->get_plugin()->get_id() ] = $data; + + return $response; + } + + + /** + * Gets the data to add to the WooCommerce REST API System Status response. + * + * Plugins can override this to add their own data. + * + * @since 5.2.0 + * + * @return array + */ + protected function get_system_status_data() { + + return array(); + } + + + /** + * Registers new WC REST API routes. + * + * @since 5.2.0 + */ + public function register_routes() { + + if ( $settings = $this->get_plugin()->get_settings_handler() ) { + + $settings_controller = new REST_API\Controllers\Settings( $settings ); + + $settings_controller->register_routes(); + } + } + + + /** + * Gets the plugin instance. + * + * @since 5.2.0 + * + * @return SV_WC_Plugin|SV_WC_Payment_Gateway_Plugin + */ + protected function get_plugin() { + + return $this->plugin; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-async-request.php b/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-async-request.php new file mode 100644 index 0000000..45c20d1 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-async-request.php @@ -0,0 +1,192 @@ +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 async request + * + * @since 4.4.0 + * @param array $data + * @return SV_WP_Async_Request + */ + public function set_data( $data ) { + $this->data = $data; + + return $this; + } + + + /** + * Dispatch the async request + * + * @since 4.4.0 + * @return array|\WP_Error + */ + public function dispatch() { + + $url = add_query_arg( $this->get_query_args(), $this->get_query_url() ); + $args = $this->get_request_args(); + + return wp_safe_remote_get( esc_url_raw( $url ), $args ); + } + + + /** + * Get query args + * + * @since 4.4.0 + * @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 + * + * @since 4.4.0 + * @return string + */ + protected function get_query_url() { + + if ( property_exists( $this, 'query_url' ) ) { + return $this->query_url; + } + + return admin_url( 'admin-ajax.php' ); + } + + + /** + * Get request args + * + * In 4.6.3 renamed from get_post_args to get_request_args + * + * @since 4.4.0 + * @return array + */ + protected function get_request_args() { + + if ( property_exists( $this, 'request_args' ) ) { + return $this->request_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. + * @since 4.4.0 + */ + public function maybe_handle() { + check_ajax_referer( $this->identifier, 'nonce' ); + + $this->handle(); + + wp_die(); + } + + + /** + * Handle + * + * Override this method to perform any actions required + * during the async request. + * + * @since 4.4.0 + */ + abstract protected function handle(); + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php b/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php new file mode 100644 index 0000000..7e6dc92 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php @@ -0,0 +1,1136 @@ +create_job( $attrs ); + * $background_job_handler->dispatch(); + * + * @since 4.4.0 + */ +abstract class SV_WP_Background_Job_Handler extends SV_WP_Async_Request { + + + /** @var string async request prefix */ + protected $prefix = 'sv_wp'; + + /** @var string async request action */ + protected $action = 'background_job'; + + /** @var string data key */ + protected $data_key = 'data'; + + /** @var int start time of current process */ + protected $start_time = 0; + + /** @var string cron hook identifier */ + protected $cron_hook_identifier; + + /** @var string cron interval identifier */ + protected $cron_interval_identifier; + + /** @var string debug message, used by the system status tool */ + protected $debug_message; + + + /** + * Initiate new background job handler + * + * @since 4.4.0 + */ + public function __construct() { + + parent::__construct(); + + $this->cron_hook_identifier = $this->identifier . '_cron'; + $this->cron_interval_identifier = $this->identifier . '_cron_interval'; + + $this->add_hooks(); + } + + + /** + * Adds the necessary action and filter hooks. + * + * @since 4.8.0 + */ + protected function add_hooks() { + + // cron healthcheck + add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) ); + add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) ); + + // debugging & testing + add_action( "wp_ajax_nopriv_{$this->identifier}_test", array( $this, 'handle_connection_test_response' ) ); + add_filter( 'woocommerce_debug_tools', array( $this, 'add_debug_tool' ) ); + add_filter( 'gettext', array( $this, 'translate_success_message' ), 10, 3 ); + } + + + /** + * Dispatch + * + * @since 4.4.0 + * @return array|WP_Error + */ + public function dispatch() { + + // schedule the cron healthcheck + $this->schedule_event(); + + // perform remote post + return parent::dispatch(); + } + + + /** + * Maybe processes job queue. + * + * Checks whether data exists within the job queue and that the background process is not already running. + * + * @since 4.4.0 + * + * @throws \Exception upon error + */ + public function maybe_handle() { + + if ( $this->is_process_running() ) { + // background process already running + wp_die(); + } + + if ( $this->is_queue_empty() ) { + // no data to process + wp_die(); + } + + /** + * WC core does 2 things here that can interfere with our nonce check: + * + * 1. WooCommerce starts a session due to our GET request to dispatch a job + * However, this happens *after* we've generated a nonce without a session (in CRON context) + * 2. it then filters nonces for logged-out users indiscriminately without checking the nonce action; if + * there is a session created (and now the server does have one), it tries to filter every.single.nonce + * for logged-out users to use the customer session ID instead of 0 for user ID. We *want* to check + * against a UID of 0 (since that's how the nonce was created), so we temporarily pause the + * logged-out nonce hijacking before standing aside. + * + * @see \WC_Session_Handler::init() when the action is hooked + * @see \WC_Session_Handler::nonce_user_logged_out() WC < 5.3 callback + * @see \WC_Session_Handler::maybe_update_nonce_user_logged_out() WC >= 5.3 callback + */ + if ( SV_WC_Plugin_Compatibility::is_wc_version_gte('5.3') ) { + $callback = [ WC()->session, 'maybe_update_nonce_user_logged_out' ]; + $arguments = 2; + } else { + $callback = [ WC()->session, 'nonce_user_logged_out' ]; + $arguments = 1; + } + + remove_filter( 'nonce_user_logged_out', $callback ); + + check_ajax_referer( $this->identifier, 'nonce' ); + + // sorry, later nonce users! please play again + add_filter( 'nonce_user_logged_out', $callback, 10, $arguments ); + + $this->handle(); + + wp_die(); + } + + + /** + * Check whether job queue is empty or not + * + * @since 4.4.0 + * @return bool True if queue is empty, false otherwise + */ + protected function is_queue_empty() { + global $wpdb; + + $key = $this->identifier . '_job_%'; + + // only queued or processing jobs count + $queued = '%"status":"queued"%'; + $processing = '%"status":"processing"%'; + + $count = $wpdb->get_var( $wpdb->prepare( " + SELECT COUNT(*) + FROM {$wpdb->options} + WHERE option_name LIKE %s + AND ( option_value LIKE %s OR option_value LIKE %s ) + ", $key, $queued, $processing ) ); + + return ( $count > 0 ) ? false : true; + } + + + /** + * Check whether background process is running or not + * + * Check whether the current process is already running + * in a background process. + * + * @since 4.4.0 + * @return bool True if processing is running, false otherwise + */ + protected function is_process_running() { + + // add a random artificial delay to prevent a race condition if 2 or more processes are trying to + // process the job queue at the very same moment in time and neither of them have yet set the lock + // before the others are calling this method + usleep( rand( 100000, 300000 ) ); + + return (bool) get_transient( "{$this->identifier}_process_lock" ); + } + + + /** + * Lock process + * + * Lock the process so that multiple instances can't run simultaneously. + * Override if applicable, but the duration should be greater than that + * defined in the time_exceeded() method. + * + * @since 4.4.0 + */ + protected function lock_process() { + + // set start time of current process + $this->start_time = time(); + + // set lock duration to 1 minute by default + $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; + + /** + * Filter the queue lock time + * + * @since 4.4.0 + * @param int $lock_duration Lock duration in seconds + */ + $lock_duration = apply_filters( "{$this->identifier}_queue_lock_time", $lock_duration ); + + set_transient( "{$this->identifier}_process_lock", microtime(), $lock_duration ); + } + + + /** + * Unlock process + * + * Unlock the process so that other instances can spawn. + * + * @since 4.4.0 + * @return SV_WP_Background_Job_Handler + */ + protected function unlock_process() { + + delete_transient( "{$this->identifier}_process_lock" ); + + return $this; + } + + + /** + * Check if memory limit is exceeded + * + * Ensures the background job handler process never exceeds 90% + * of the maximum WordPress memory. + * + * @since 4.4.0 + * + * @return bool True if exceeded memory limit, false otherwise + */ + protected function memory_exceeded() { + + $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory + $current_memory = memory_get_usage( true ); + $return = false; + + if ( $current_memory >= $memory_limit ) { + $return = true; + } + + /** + * Filter whether memory limit has been exceeded or not + * + * @since 4.4.0 + * + * @param bool $exceeded + */ + return apply_filters( "{$this->identifier}_memory_exceeded", $return ); + } + + + /** + * Get memory limit + * + * @since 4.4.0 + * + * @return int memory limit in bytes + */ + protected function get_memory_limit() { + + if ( function_exists( 'ini_get' ) ) { + $memory_limit = ini_get( 'memory_limit' ); + } else { + // sensible default + $memory_limit = '128M'; + } + + if ( ! $memory_limit || -1 === (int) $memory_limit ) { + // unlimited, set to 32GB + $memory_limit = '32G'; + } + + return SV_WC_Plugin_Compatibility::convert_hr_to_bytes( $memory_limit ); + } + + + /** + * Check whether request time limit has been exceeded or not + * + * Ensures the background job handler never exceeds a sensible time limit. + * A timeout limit of 30s is common on shared hosting. + * + * @since 4.4.0 + * + * @return bool True, if time limit exceeded, false otherwise + */ + protected function time_exceeded() { + + /** + * Filter default time limit for background job execution, defaults to + * 20 seconds + * + * @since 4.4.0 + * + * @param int $time Time in seconds + */ + $finish = $this->start_time + apply_filters( "{$this->identifier}_default_time_limit", 20 ); + $return = false; + + if ( time() >= $finish ) { + $return = true; + } + + /** + * Filter whether maximum execution time has exceeded or not + * + * @since 4.4.0 + * @param bool $exceeded true if execution time exceeded, false otherwise + */ + return apply_filters( "{$this->identifier}_time_exceeded", $return ); + } + + + /** + * Create a background job + * + * Delicious Brains' versions alternative would be using ->data()->save(). + * Allows passing in any kind of job attributes, which will be available at item data processing time. + * This allows sharing common options between items without the need to repeat + * the same information for every single item in queue. + * + * Instead of returning self, returns the job instance, which gives greater + * control over the job. + * + * @since 4.4.0 + * + * @param array|mixed $attrs Job attributes. + * @return \stdClass|object|null + */ + public function create_job( $attrs ) { + global $wpdb; + + if ( empty( $attrs ) ) { + return null; + } + + // generate a unique ID for the job + $job_id = md5( microtime() . mt_rand() ); + + /** + * Filter new background job attributes + * + * @since 4.4.0 + * + * @param array $attrs Job attributes + * @param string $id Job ID + */ + $attrs = apply_filters( "{$this->identifier}_new_job_attrs", $attrs, $job_id ); + + // ensure a few must-have attributes + $attrs = wp_parse_args( array( + 'id' => $job_id, + 'created_at' => current_time( 'mysql' ), + 'created_by' => get_current_user_id(), + 'status' => 'queued', + ), $attrs ); + + $wpdb->insert( $wpdb->options, array( + 'option_name' => "{$this->identifier}_job_{$job_id}", + 'option_value' => json_encode( $attrs ), + 'autoload' => 'no' + ) ); + + $job = new \stdClass(); + + foreach ( $attrs as $key => $value ) { + $job->{$key} = $value; + } + + /** + * Runs when a job is created. + * + * @since 4.4.0 + * + * @param \stdClass|object $job the created job + */ + do_action( "{$this->identifier}_job_created", $job ); + + return $job; + } + + + /** + * Get a job (by default the first in the queue) + * + * @since 4.4.0 + * + * @param string $id Optional. Job ID. Will return first job in queue if not + * provided. Will not return completed or failed jobs from queue. + * @return \stdClass|object|null The found job object or null + */ + public function get_job( $id = null ) { + global $wpdb; + + if ( ! $id ) { + + $key = $this->identifier . '_job_%'; + $queued = '%"status":"queued"%'; + $processing = '%"status":"processing"%'; + + $results = $wpdb->get_var( $wpdb->prepare( " + SELECT option_value + FROM {$wpdb->options} + WHERE option_name LIKE %s + AND ( option_value LIKE %s OR option_value LIKE %s ) + ORDER BY option_id ASC + LIMIT 1 + ", $key, $queued, $processing ) ); + + } else { + + $results = $wpdb->get_var( $wpdb->prepare( " + SELECT option_value + FROM {$wpdb->options} + WHERE option_name = %s + ", "{$this->identifier}_job_{$id}" ) ); + + } + + if ( ! empty( $results ) ) { + + $job = new \stdClass(); + + foreach ( json_decode( $results, true ) as $key => $value ) { + $job->{$key} = $value; + } + + } else { + return null; + } + + /** + * Filters the job as returned from the database. + * + * @since 4.4.0 + * + * @param \stdClass|object $job + */ + return apply_filters( "{$this->identifier}_returned_job", $job ); + } + + + /** + * Gets jobs. + * + * @since 4.4.2 + * + * @param array $args { + * Optional. An array of arguments + * + * @type string|array $status Job status(es) to include + * @type string $order ASC or DESC. Defaults to DESC + * @type string $orderby Field to order by. Defaults to option_id + * } + * @return \stdClass[]|object[]|null Found jobs or null if none found + */ + public function get_jobs( $args = array() ) { + global $wpdb; + + $args = wp_parse_args( $args, array( + 'order' => 'DESC', + 'orderby' => 'option_id', + ) ); + + $replacements = array( $this->identifier . '_job_%' ); + $status_query = ''; + + // prepare status query + if ( ! empty( $args['status'] ) ) { + + $statuses = (array) $args['status']; + $placeholders = array(); + + foreach ( $statuses as $status ) { + + $placeholders[] = '%s'; + $replacements[] = '%"status":"' . sanitize_key( $status ) . '"%'; + } + + $status_query = 'AND ( option_value LIKE ' . implode( ' OR option_value LIKE ', $placeholders ) . ' )'; + } + + // prepare sorting vars + $order = sanitize_key( $args['order'] ); + $orderby = sanitize_key( $args['orderby'] ); + + // put it all together now + $query = $wpdb->prepare( " + SELECT option_value + FROM {$wpdb->options} + WHERE option_name LIKE %s + {$status_query} + ORDER BY {$orderby} {$order} + ", $replacements ); + + $results = $wpdb->get_col( $query ); + + if ( empty( $results ) ) { + return null; + } + + $jobs = array(); + + foreach ( $results as $result ) { + + $job = new \stdClass(); + + foreach ( json_decode( $result, true ) as $key => $value ) { + $job->{$key} = $value; + } + + /** This filter is documented above */ + $job = apply_filters( "{$this->identifier}_returned_job", $job ); + + $jobs[] = $job; + } + + return $jobs; + } + + + /** + * Handles jobs. + * + * Process jobs while remaining within server memory and time limit constraints. + * + * @since 4.4.0 + * + * @throws \Exception + */ + protected function handle() { + + $this->lock_process(); + + do { + + // Get next job in the queue + $job = $this->get_job(); + + // handle PHP errors from here on out + register_shutdown_function( array( $this, 'handle_shutdown' ), $job ); + + // Start processing + $this->process_job( $job ); + + } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() ); + + $this->unlock_process(); + + // Start next job or complete process + if ( ! $this->is_queue_empty() ) { + $this->dispatch(); + } else { + $this->complete(); + } + + wp_die(); + } + + + /** + * Process a job + * + * Default implementation is to loop over job data and passing each item to + * the item processor. Subclasses are, however, welcome to override this method + * to create totally different job processing implementations - see + * WC_CSV_Import_Suite_Background_Import in CSV Import for an example. + * + * If using the default implementation, the job must have a $data_key property set. + * Subclasses can override the data key, but the contents must be an array which + * the job processor can loop over. By default, the data key is `data`. + * + * If no data is set, the job will completed right away. + * + * @since 4.4.0 + * + * @param \stdClass|object $job + * @param int $items_per_batch number of items to process in a single request. Defaults to unlimited. + * @throws \Exception when job data is incorrect + * @return \stdClass $job + */ + public function process_job( $job, $items_per_batch = null ) { + + if ( ! $this->start_time ) { + $this->start_time = time(); + } + + // Indicate that the job has started processing + if ( 'processing' !== $job->status ) { + + $job->status = 'processing'; + $job->started_processing_at = current_time( 'mysql' ); + + $job = $this->update_job( $job ); + } + + $data_key = $this->data_key; + + if ( ! isset( $job->{$data_key} ) ) { + throw new \Exception( sprintf( __( 'Job data key "%s" not set', 'woocommerce-plugin-framework' ), $data_key ) ); + } + + if ( ! is_array( $job->{$data_key} ) ) { + throw new \Exception( sprintf( __( 'Job data key "%s" is not an array', 'woocommerce-plugin-framework' ), $data_key ) ); + } + + $data = $job->{$data_key}; + + $job->total = count( $data ); + + // progress indicates how many items have been processed, it + // does NOT indicate the processed item key in any way + if ( ! isset( $job->progress ) ) { + $job->progress = 0; + } + + // skip already processed items + if ( $job->progress && ! empty( $data ) ) { + $data = array_slice( $data, $job->progress, null, true ); + } + + // loop over unprocessed items and process them + if ( ! empty( $data ) ) { + + $processed = 0; + $items_per_batch = (int) $items_per_batch; + + foreach ( $data as $item ) { + + // process the item + $this->process_item( $item, $job ); + + $processed++; + $job->progress++; + + // update job progress + $job = $this->update_job( $job ); + + // job limits reached + if ( ( $items_per_batch && $processed >= $items_per_batch ) || $this->time_exceeded() || $this->memory_exceeded() ) { + break; + } + } + } + + // complete current job + if ( $job->progress >= count( $job->{$data_key} ) ) { + $job = $this->complete_job( $job ); + } + + return $job; + } + + + /** + * Update job attrs + * + * @since 4.4.0 + * + * @param \stdClass|object|string $job Job instance or ID + * @return \stdClass|object|false on failure + */ + public function update_job( $job ) { + + if ( is_string( $job ) ) { + $job = $this->get_job( $job ); + } + + if ( ! $job ) { + return false; + } + + $job->updated_at = current_time( 'mysql' ); + + $this->update_job_option( $job ); + + /** + * Runs when a job is updated. + * + * @since 4.4.0 + * + * @param \stdClass|object $job the updated job + */ + do_action( "{$this->identifier}_job_updated", $job ); + + return $job; + } + + + /** + * Handles job completion. + * + * @since 4.4.0 + * + * @param \stdClass|object|string $job Job instance or ID + * @return \stdClass|object|false on failure + */ + public function complete_job( $job ) { + + if ( is_string( $job ) ) { + $job = $this->get_job( $job ); + } + + if ( ! $job ) { + return false; + } + + $job->status = 'completed'; + $job->completed_at = current_time( 'mysql' ); + + $this->update_job_option( $job ); + + /** + * Runs when a job is completed. + * + * @since 4.4.0 + * + * @param \stdClass|object $job the completed job + */ + do_action( "{$this->identifier}_job_complete", $job ); + + return $job; + } + + + /** + * Handle job failure + * + * Default implementation does not call this method directly, but it's + * provided as a convenience method for subclasses that may call this to + * indicate that a particular job has failed for some reason. + * + * @since 4.4.0 + * + * @param \stdClass|object|string $job Job instance or ID + * @param string $reason Optional. Reason for failure. + * @return \stdClass|false on failure + */ + public function fail_job( $job, $reason = '' ) { + + if ( is_string( $job ) ) { + $job = $this->get_job( $job ); + } + + if ( ! $job ) { + return false; + } + + $job->status = 'failed'; + $job->failed_at = current_time( 'mysql' ); + + if ( $reason ) { + $job->failure_reason = $reason; + } + + $this->update_job_option( $job ); + + /** + * Runs when a job is failed. + * + * @since 4.4.0 + * + * @param \stdClass|object $job the failed job + */ + do_action( "{$this->identifier}_job_failed", $job ); + + return $job; + } + + + /** + * Delete a job + * + * @since 4.4.2 + * + * @param \stdClass|object|string $job Job instance or ID + * @return false on failure + */ + public function delete_job( $job ) { + global $wpdb; + + if ( is_string( $job ) ) { + $job = $this->get_job( $job ); + } + + if ( ! $job ) { + return false; + } + + $wpdb->delete( $wpdb->options, array( 'option_name' => "{$this->identifier}_job_{$job->id}" ) ); + + /** + * Runs after a job is deleted. + * + * @since 4.4.2 + * + * @param \stdClass|object $job the job that was deleted from database + */ + do_action( "{$this->identifier}_job_deleted", $job ); + } + + + /** + * Handle job queue completion + * + * Override if applicable, but ensure that the below actions are + * performed, or, call parent::complete(). + * + * @since 4.4.0 + */ + protected function complete() { + + // unschedule the cron healthcheck + $this->clear_scheduled_event(); + } + + + /** + * Schedule cron healthcheck + * + * @since 4.4.0 + * @param array $schedules + * @return array + */ + public function schedule_cron_healthcheck( $schedules ) { + + $interval = property_exists( $this, 'cron_interval' ) ? $this->cron_interval : 5; + + /** + * Filter cron health check interval + * + * @since 4.4.0 + * @param int $interval Interval in minutes + */ + $interval = apply_filters( "{$this->identifier}_cron_interval", $interval ); + + // adds every 5 minutes to the existing schedules. + $schedules[ $this->identifier . '_cron_interval' ] = array( + 'interval' => MINUTE_IN_SECONDS * $interval, + 'display' => sprintf( __( 'Every %d Minutes' ), $interval ), + ); + + return $schedules; + } + + + /** + * Handle cron healthcheck + * + * Restart the background process if not already running + * and data exists in the queue. + * + * @since 4.4.0 + */ + public function handle_cron_healthcheck() { + + if ( $this->is_process_running() ) { + // background process already running + exit; + } + + if ( $this->is_queue_empty() ) { + // no data to process + $this->clear_scheduled_event(); + exit; + } + + $this->dispatch(); + } + + + /** + * Schedule cron health check event + * + * @since 4.4.0 + */ + protected function schedule_event() { + + if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) { + + // schedule the health check to fire after 30 seconds from now, as to not create a race condition + // with job process lock on servers that fire & handle cron events instantly + wp_schedule_event( time() + 30, $this->cron_interval_identifier, $this->cron_hook_identifier ); + } + } + + + /** + * Clear scheduled health check event + * + * @since 4.4.0 + */ + protected function clear_scheduled_event() { + + $timestamp = wp_next_scheduled( $this->cron_hook_identifier ); + + if ( $timestamp ) { + wp_unschedule_event( $timestamp, $this->cron_hook_identifier ); + } + } + + + /** + * Process an item from job data + * + * Implement this method to perform any actions required on each + * item in job data. + * + * @since 4.4.2 + * + * @param mixed $item Job data item to iterate over + * @param \stdClass|object $job Job instance + * @return mixed + */ + abstract protected function process_item( $item, $job ); + + + /** + * Handles PHP shutdown, say after a fatal error. + * + * @since 4.5.0 + * + * @param \stdClass|object $job the job being processed + */ + public function handle_shutdown( $job ) { + + $error = error_get_last(); + + // if shutting down because of a fatal error, fail the job + if ( $error && E_ERROR === $error['type'] ) { + + $this->fail_job( $job, $error['message'] ); + + $this->unlock_process(); + } + } + + + /** + * Update a job option in options database. + * + * @since 4.6.3 + * + * @param \stdClass|object $job the job instance to update in database + * @return int|bool number of rows updated or false on failure, see wpdb::update() + */ + private function update_job_option( $job ) { + global $wpdb; + + return $wpdb->update( + $wpdb->options, + array( 'option_value' => json_encode( $job ) ), + array( 'option_name' => "{$this->identifier}_job_{$job->id}" ) + ); + } + + + /** Debug & Testing Methods ***********************************************/ + + + /** + * Tests the background handler's connection. + * + * @since 4.8.0 + * + * @return bool + */ + public function test_connection() { + + $test_url = add_query_arg( 'action', "{$this->identifier}_test", admin_url( 'admin-ajax.php' ) ); + $result = wp_safe_remote_get( $test_url ); + $body = ! is_wp_error( $result ) ? wp_remote_retrieve_body( $result ) : null; + + // some servers may add a UTF8-BOM at the beginning of the response body, so we check if our test + // string is included in the body, as an equal check would produce a false negative test result + return $body && SV_WC_Helper::str_exists( $body, '[TEST_LOOPBACK]' ); + } + + + /** + * Handles the connection test request. + * + * @since 4.8.0 + */ + public function handle_connection_test_response() { + + echo '[TEST_LOOPBACK]'; + exit; + } + + + /** + * Adds the WooCommerce debug tool. + * + * @since 4.8.0 + * + * @param array $tools WooCommerce core tools + * @return array + */ + public function add_debug_tool( $tools ) { + + // this key is not unique to the plugin to avoid duplicate tools + $tools['sv_wc_background_job_test'] = array( + 'name' => __( 'Background Processing Test', 'woocommerce-plugin-framework' ), + 'button' => __( 'Run Test', 'woocommerce-plugin-framework' ), + 'desc' => __( 'This tool will test whether your server is capable of processing background jobs.', 'woocommerce-plugin-framework' ), + 'callback' => array( $this, 'run_debug_tool' ), + ); + + return $tools; + } + + + /** + * Runs the test connection debug tool. + * + * @since 4.8.0 + * + * @return string + */ + public function run_debug_tool() { + + if ( $this->test_connection() ) { + $this->debug_message = esc_html__( 'Success! You should be able to process background jobs.', 'woocommerce-plugin-framework' ); + $result = true; + } else { + $this->debug_message = esc_html__( 'Could not connect. Please ask your hosting company to ensure your server has loopback connections enabled.', 'woocommerce-plugin-framework' ); + $result = false; + } + + return $result; + } + + + /** + * Translate the tool success message. + * + * This can be removed in favor of returning the message string in `run_debug_tool()` + * when WC 3.1 is required, though that means the message will always be "success" styled. + * + * @since 4.8.0 + * + * @param string $translated the text to output + * @param string $original the original text + * @param string $domain the textdomain + * @return string the updated text + */ + public function translate_success_message( $translated, $original, $domain ) { + + if ( 'woocommerce' === $domain && ( 'Tool ran.' === $original || 'There was an error calling %s' === $original ) ) { + $translated = $this->debug_message; + } + + return $translated; + } + + + /** Helper Methods ********************************************************/ + + + /** + * Gets the job handler identifier. + * + * @since 4.8.0 + * + * @return string + */ + public function get_identifier() { + + return $this->identifier; + } + + +} + + +endif; diff --git a/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-job-batch-handler.php b/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-job-batch-handler.php new file mode 100644 index 0000000..1386061 --- /dev/null +++ b/vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-job-batch-handler.php @@ -0,0 +1,310 @@ +job_handler = $job_handler; + $this->plugin = $plugin; + + $this->add_hooks(); + + $this->render_js(); + } + + + /** + * Adds the necessary action and filter hooks. + * + * @since 4.8.0 + */ + protected function add_hooks() { + + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); + + add_action( 'wp_ajax_' . $this->get_job_handler()->get_identifier() . '_process_batch', array( $this, 'ajax_process_batch' ) ); + add_action( 'wp_ajax_' . $this->get_job_handler()->get_identifier() . '_cancel_job', array( $this, 'ajax_cancel_job' ) ); + } + + + /** + * Enqueues the scripts. + * + * @since 4.8.0 + */ + public function enqueue_scripts() { + + wp_enqueue_script( $this->get_job_handler()->get_identifier() . '_batch_handler', $this->get_plugin()->get_framework_assets_url() . '/js/admin/sv-wp-admin-job-batch-handler.min.js', array( 'jquery' ), $this->get_plugin()->get_version() ); + } + + + /** + * Renders the inline JavaScript for instantiating the batch handler class. + * + * @since 4.8.0 + */ + protected function render_js() { + + /** + * Filters the JavaScript batch handler arguments. + * + * @since 4.8.0 + * + * @param array $args arguments to pass to the JavaScript batch handler + * @param SV_WP_Job_Batch_Handler $handler handler object + */ + $args = apply_filters( $this->get_job_handler()->get_identifier() . '_batch_handler_js_args', $this->get_js_args(), $this ); + + wc_enqueue_js( sprintf( 'window.%1$s_batch_handler = new %2$s( %3$s );', + esc_js( $this->get_job_handler()->get_identifier() ), + esc_js( $this->get_js_class() ), + json_encode( $args ) + ) ); + } + + + /** + * Gets the JavaScript batch handler arguments. + * + * @since 4.8.0 + * + * @return array + */ + protected function get_js_args() { + + return array( + 'id' => $this->get_job_handler()->get_identifier(), + 'process_nonce' => wp_create_nonce( $this->get_job_handler()->get_identifier() . '_process_batch' ), + 'cancel_nonce' => wp_create_nonce( $this->get_job_handler()->get_identifier() . '_cancel_job' ), + ); + } + + + /** + * Gets the JavaScript batch handler class name. + * + * Plugins can override this with their own handler that extends the base. + * + * @since 4.8.0 + * + * @return string + */ + protected function get_js_class() { + + return 'SV_WP_Job_Batch_Handler'; + } + + + /** + * Processes a job batch via AJAX. + * + * @internal + * + * @since 4.8.0 + * + * @throws \Exception upon error. + */ + public function ajax_process_batch() { + + check_ajax_referer( $this->get_job_handler()->get_identifier() . '_process_batch', 'security' ); + + if ( empty( $_POST['job_id'] ) ) { + return; + } + + try { + + $job = $this->process_batch( $_POST['job_id'] ); + + $job = $this->process_job_status( $job ); + + wp_send_json_success( (array) $job ); + + } catch( SV_WC_Plugin_Exception $e ) { + + $data = ( ! empty( $job ) ) ? (array) $job : array(); + + $data['message'] = $e->getMessage(); + + wp_send_json_error( $data ); + } + } + + + /** + * Cancels a job via AJAX. + * + * @internal + * + * @since 4.8.0 + */ + public function ajax_cancel_job() { + + check_ajax_referer( $this->get_job_handler()->get_identifier() . '_cancel_job', 'security' ); + + if ( empty( $_POST['job_id'] ) ) { + return; + } + + $this->get_job_handler()->delete_job( $_POST['job_id'] ); + + wp_send_json_success(); + } + + + /** + * Handles a job after processing one of its batches. + * + * Allows plugins to add extra job properties and handle certain statuses. + * Implementations may throw a SV_WC_Plugin_Exception. + * + * @since 4.8.0 + * + * @param \stdClass|object $job job object + * @return \stdClass|object $job job object + */ + protected function process_job_status( $job ) { + + $job->percentage = SV_WC_Helper::number_format( (int) $job->progress / (int) $job->total * 100 ); + + return $job; + } + + + /** + * Processes a batch of items for the given job. + * + * A batch consists of the number of items defined by self::get_items_per_batch() + * or the number we're able to process before exceeding time or memory limits. + * + * @since 4.8.0 + * + * @param string $job_id job to process + * @return \stdClass|object $job job after processing the batch + * @throws \Exception + * @throws SV_WC_Plugin_Exception + */ + public function process_batch( $job_id ) { + + $job = $this->get_job_handler()->get_job( $job_id ); + + if ( ! $job ) { + throw new SV_WC_Plugin_Exception( 'Invalid job ID' ); + } + + return $this->get_job_handler()->process_job( $job, $this->get_items_per_batch() ); + } + + + /** + * Gets the number of items to process in a single request when processing job item batches. + * + * @since 4.8.0 + * + * @return int + */ + protected function get_items_per_batch() { + + /** + * Filters the number of items to process in a single request when processing job item batches. + * + * @since 4.8.0 + * + * @param int $items_per_batch + */ + $items_per_batch = absint( apply_filters( $this->get_job_handler()->get_identifier() . '_batch_handler_items_per_batch', $this->items_per_batch ) ); + + return $items_per_batch > 0 ? $items_per_batch : 1; + } + + + /** + * Gets the job handler. + * + * @since 4.8.0 + * + * @return SV_WP_Background_Job_Handler + */ + protected function get_job_handler() { + + return $this->job_handler; + } + + + /** + * Gets the plugin instance. + * + * @since 4.8.0 + * + * @return SV_WC_Plugin + */ + protected function get_plugin() { + + return $this->plugin; + } + + +} + + +endif; diff --git a/woocommerce-product-documents.php b/woocommerce-product-documents.php new file mode 100644 index 0000000..8555809 --- /dev/null +++ b/woocommerce-product-documents.php @@ -0,0 +1,390 @@ +is_environment_compatible() ) { + + add_action( 'plugins_loaded', array( $this, 'init_plugin' ) ); + } + } + + + /** + * Cloning instances is forbidden due to singleton pattern. + * + * @since 1.9.0 + */ + public function __clone() { + + _doing_it_wrong( __FUNCTION__, sprintf( 'You cannot clone instances of %s.', get_class( $this ) ), '1.9.0' ); + } + + + /** + * Unserializing instances is forbidden due to singleton pattern. + * + * @since 1.9.0 + */ + public function __wakeup() { + + _doing_it_wrong( __FUNCTION__, sprintf( 'You cannot unserialize instances of %s.', get_class( $this ) ), '1.9.0' ); + } + + + /** + * Initializes the plugin. + * + * @since 1.9.0 + */ + public function init_plugin() { + + if ( $this->plugins_compatible() ) { + + $this->load_framework(); + + // load the main plugin class + require_once( plugin_dir_path( __FILE__ ) . 'class-wc-product-documents.php' ); + + // fire it up! + wc_product_documents(); + } + } + + + /** + * Loads the base framework classes. + * + * @since 1.9.0 + */ + protected function load_framework() { + + if ( ! class_exists( '\\SkyVerge\\WooCommerce\\PluginFramework\\' . $this->get_framework_version_namespace() . '\\SV_WC_Plugin' ) ) { + + require_once( plugin_dir_path( __FILE__ ) . 'vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php' ); + } + } + + + /** + * Returns the framework version in namespace form. + * + * @since 1.9.0 + * + * @return string + */ + protected function get_framework_version_namespace() { + + return 'v' . str_replace( '.', '_', $this->get_framework_version() ); + } + + + /** + * Returns the framework version used by this plugin. + * + * @since 1.9.0 + * + * @return string + */ + protected function get_framework_version() { + + return self::FRAMEWORK_VERSION; + } + + + /** + * Checks the server environment and other factors and deactivates plugins as necessary. + * + * Based on http://wptavern.com/how-to-prevent-wordpress-plugins-from-activating-on-sites-with-incompatible-hosting-environments + * + * @since 1.9.0 + */ + public function activation_check() { + + if ( ! $this->is_environment_compatible() ) { + + $this->deactivate_plugin(); + + wp_die( self::PLUGIN_NAME . ' could not be activated. ' . $this->get_environment_message() ); + } + } + + + /** + * Checks the environment on loading WordPress, just in case the environment changes after activation. + * + * @since 1.9.0 + */ + public function check_environment() { + + if ( ! $this->is_environment_compatible() && is_plugin_active( plugin_basename( __FILE__ ) ) ) { + + $this->deactivate_plugin(); + + $this->add_admin_notice( 'bad_environment', 'error', self::PLUGIN_NAME . ' has been deactivated. ' . $this->get_environment_message() ); + } + } + + + /** + * Adds notices for out-of-date WordPress and/or WooCommerce versions. + * + * @since 1.9.0 + */ + public function add_plugin_notices() { + + if ( ! $this->is_wp_compatible() ) { + + $this->add_admin_notice( 'update_wordpress', 'error', sprintf( + '%s requires WordPress version %s or higher. Please %supdate WordPress »%s', + '' . self::PLUGIN_NAME . '', + self::MINIMUM_WP_VERSION, + '', '' + ) ); + } + + if ( ! $this->is_wc_compatible() ) { + + $this->add_admin_notice( 'update_woocommerce', 'error', sprintf( + '%s requires WooCommerce version %s or higher. Please %supdate WooCommerce »%s', + '' . self::PLUGIN_NAME . '', + self::MINIMUM_WC_VERSION, + '', '' + ) ); + } + } + + + /** + * Determines if the required plugins are compatible. + * + * @since 1.9.0 + * + * @return bool + */ + protected function plugins_compatible() { + + return $this->is_wp_compatible() && $this->is_wc_compatible(); + } + + + /** + * Determines if the WordPress compatible. + * + * @since 1.9.0 + * + * @return bool + */ + protected function is_wp_compatible() { + + return version_compare( get_bloginfo( 'version' ), self::MINIMUM_WP_VERSION, '>=' ); + } + + + /** + * Determines if the WooCommerce compatible. + * + * @since 1.9.0 + * + * @return bool + */ + protected function is_wc_compatible() { + + return defined( 'WC_VERSION' ) && version_compare( WC_VERSION, self::MINIMUM_WC_VERSION, '>=' ); + } + + + /** + * Deactivates the plugin. + * + * @since 1.9.0 + */ + protected function deactivate_plugin() { + + deactivate_plugins( plugin_basename( __FILE__ ) ); + + if ( isset( $_GET['activate'] ) ) { + unset( $_GET['activate'] ); + } + } + + + /** + * Adds an admin notice to be displayed. + * + * @since 1.9.0 + * + * @param string $slug the notice slug + * @param string $class the notice class + * @param string $message the notice message body + */ + public function add_admin_notice( $slug, $class, $message ) { + + $this->notices[ $slug ] = array( + 'class' => $class, + 'message' => $message + ); + } + + + /** + * Displays any admin notices added with \SV_WC_Framework_Plugin_Loader::add_admin_notice() + * + * @internal + * + * @since 1.9.0 + */ + public function admin_notices() { + + foreach ( (array) $this->notices as $notice_key => $notice ) : + + ?> +
    +

    array( 'href' => array() ) ) ); ?>

    +
    + =' ); + } + + + /** + * Returns the message for display when the environment is incompatible with this plugin. + * + * @since 1.9.0 + * + * @return string + */ + protected function get_environment_message() { + + return sprintf( 'The minimum PHP version required for this plugin is %1$s. You are running %2$s.', self::MINIMUM_PHP_VERSION, PHP_VERSION ); + } + + + /** + * Returns the main plugin loader instance. + * + * Ensures only one instance can be loaded. + * + * @since 1.9.0 + * + * @return \WC_Product_Documents_Loader + */ + public static function instance() { + + if ( null === self::$instance ) { + + self::$instance = new self(); + } + + return self::$instance; + } + + +} + + +// fire it up! +WC_Product_Documents_Loader::instance();