first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,277 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Assets' ) ) :
class Assets {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts_styles' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'backend_scripts_styles' ) );
}
/**
* Load styles & scripts
*/
public function frontend_scripts_styles ( $hook ) {
# none yet
}
/**
* Load styles & scripts
*/
public function backend_scripts_styles ( $hook ) {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
global $wp_version;
if ( WPO_WCPDF()->admin->is_order_page() ) {
// STYLES
wp_enqueue_style( 'thickbox' );
wp_enqueue_style(
'wpo-wcpdf-order-styles',
WPO_WCPDF()->plugin_url() . '/assets/css/order-styles'.$suffix.'.css',
array(),
WPO_WCPDF_VERSION
);
if ( version_compare( $wp_version, '5.3', '<' ) ) {
// WC2.1 - WC3.2 (MP6) is used: bigger buttons
// also applied to WC3.3+ but without affect due to .column-order_actions class being deprecated in 3.3+
wp_enqueue_style(
'wpo-wcpdf-order-styles-buttons',
WPO_WCPDF()->plugin_url() . '/assets/css/order-styles-buttons-wc38'.$suffix.'.css',
array(),
WPO_WCPDF_VERSION
);
} elseif ( version_compare( $wp_version, '5.3', '>=' ) ) {
// WP5.3 or newer is used: realign img inside buttons
wp_enqueue_style(
'wpo-wcpdf-order-styles-buttons',
WPO_WCPDF()->plugin_url() . '/assets/css/order-styles-buttons-wc39'.$suffix.'.css',
array(),
WPO_WCPDF_VERSION
);
}
// SCRIPTS
wp_enqueue_script(
'wpo-wcpdf',
WPO_WCPDF()->plugin_url() . '/assets/js/order-script'.$suffix.'.js',
array( 'jquery', 'jquery-blockui' ),
WPO_WCPDF_VERSION
);
wp_localize_script(
'wpo-wcpdf',
'wpo_wcpdf_ajax',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ), // URL to WordPress ajax handling page
'nonce' => wp_create_nonce( 'generate_wpo_wcpdf' ),
'bulk_actions' => array_keys( wcpdf_get_bulk_actions() ),
'select_orders' => __( 'You have to select order(s) first!', 'woocommerce-pdf-invoices-packing-slips'),
'confirm_delete' => __( 'Are you sure you want to delete this document? This cannot be undone.', 'woocommerce-pdf-invoices-packing-slips'),
'confirm_regenerate' => __( 'Are you sure you want to regenerate this document? This will make the document reflect the most current settings (such as footer text, document name, etc.) rather than using historical settings.', 'woocommerce-pdf-invoices-packing-slips'),
'sticky_document_data_metabox' => apply_filters( 'wpo_wcpdf_sticky_document_data_metabox', true ),
)
);
}
// only load on our own settings page
// maybe find a way to refer directly to WPO\WC\PDF_Invoices\Settings::$options_page_hook ?
if ( $hook == 'woocommerce_page_wpo_wcpdf_options_page' || $hook == 'settings_page_wpo_wcpdf_options_page' || ( isset($_GET['page']) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
wp_enqueue_style(
'wpo-wcpdf-settings-styles',
WPO_WCPDF()->plugin_url() . '/assets/css/settings-styles'.$suffix.'.css',
array('woocommerce_admin_styles'),
WPO_WCPDF_VERSION
);
wp_add_inline_style( 'wpo-wcpdf-settings-styles', ".next-number-input.ajax-waiting {
background-image: url(".WPO_WCPDF()->plugin_url().'/assets/images/spinner.gif'.") !important;
background-position: 95% 50% !important;
background-repeat: no-repeat !important;
}" );
wp_add_inline_style( 'wpo-wcpdf-settings-styles', "#preview-order-search.ajax-waiting {
background-image: url(".WPO_WCPDF()->plugin_url().'/assets/images/spinner.gif'.") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
}" );
wp_add_inline_style( 'wpo-wcpdf-settings-styles', "#wpo-wcpdf-preview-wrapper .slider.slide-left:after {
content: '".__( 'Preview', 'woocommerce-pdf-invoices-packing-slips' )."';
}
#wpo-wcpdf-preview-wrapper .slider.slide-right:after {
content: '".__( 'Settings', 'woocommerce-pdf-invoices-packing-slips' )."';
}" );
wp_add_inline_style( 'wpo-wcpdf-settings-styles', "#upgrade-table td span.feature-available {
background-image: url(".WPO_WCPDF()->plugin_url().'/assets/images/checkmark.svg'.") !important;
}" );
// SCRIPTS
wp_enqueue_script( 'wc-enhanced-select' );
wp_enqueue_script(
'wpo-wcpdf-admin',
WPO_WCPDF()->plugin_url() . '/assets/js/admin-script'.$suffix.'.js',
array( 'jquery', 'wc-enhanced-select', 'jquery-blockui', 'jquery-tiptip' ),
WPO_WCPDF_VERSION
);
wp_localize_script(
'wpo-wcpdf-admin',
'wpo_wcpdf_admin',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'template_paths' => WPO_WCPDF()->settings->get_installed_templates(),
'pdfjs_worker' => WPO_WCPDF()->plugin_url() . '/assets/js/pdf_js/pdf.worker.min.js', // taken from https://cdnjs.com/libraries/pdf.js
'preview_excluded_settings' => apply_filters( 'wpo_wcpdf_preview_excluded_settings', array(
// general
'download_display',
'test_mode',
// document
'enabled',
'archive_pdf',
'auto_generate_for_statuses',
'attach_to_email_ids',
'disable_for_statuses',
'reset_number_yearly',
'my_account_buttons',
'invoice_number_column',
'invoice_date_column',
'disable_free',
'use_latest_settings',
'mark_printed',
'unmark_printed',
'include_encrypted_pdf'
) ),
'pointers' => array(
'wcpdf_document_settings_sections' => array(
'target' => '.wcpdf_document_settings_sections',
'content' => sprintf(
'<h3>%s</h3><p>%s</p>',
__( 'Document settings', 'woocommerce-pdf-invoices-packing-slips' ),
__( 'Select a document in the dropdown menu above to edit its settings.', 'woocommerce-pdf-invoices-packing-slips' )
),
'pointer_class' => 'wp-pointer arrow-top wpo-wcpdf-pointer',
'pointer_width' => 300,
'position' => array(
'edge' => 'top',
'align' => 'left',
),
),
),
'dismissed_pointers' => get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ),
'mysql_int_size_limit' => __( 'The number should be smaller than 2147483647. Please note you should add your next document number without prefix, suffix or padding.', 'woocommerce-pdf-invoices-packing-slips' ),
)
);
// preview PDFJS
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
if ( ! isset( $debug_settings['disable_preview'] ) ) {
wp_enqueue_script(
'wpo-wcpdf-pdfjs',
WPO_WCPDF()->plugin_url() . '/assets/js/pdf_js/pdf.min.js', // taken from https://cdnjs.com/libraries/pdf.js
array(),
'3.7.107'
);
}
wp_enqueue_media();
wp_enqueue_script(
'wpo-wcpdf-media-upload',
WPO_WCPDF()->plugin_url() . '/assets/js/media-upload'.$suffix.'.js',
array( 'jquery' ),
WPO_WCPDF_VERSION
);
if ( wp_script_is( 'wp-pointer', 'enqueued' ) === false ) {
wp_enqueue_script( 'wp-pointer' );
}
if ( wp_style_is( 'wp-pointer', 'enqueued' ) === false ) {
wp_enqueue_style( 'wp-pointer' );
}
}
if (
$hook === 'woocommerce_page_wc-admin' &&
WPO_WCPDF()->order_util->is_wc_admin_page()
) {
wp_enqueue_script(
'wpo-wcpdf-analytics-order',
WPO_WCPDF()->plugin_url() . '/assets/js/analytics-order' . $suffix . '.js',
array( 'wp-hooks' ),
WPO_WCPDF_VERSION,
true
);
wp_localize_script(
'wpo-wcpdf-analytics-order',
'wpo_wcpdf_analytics_order',
array(
'label' => __( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ),
)
);
}
// status/debug page scripts
if ( isset( $_REQUEST['page'] ) && $_REQUEST['page'] == 'wpo_wcpdf_options_page' && isset( $_REQUEST['tab'] ) && $_REQUEST['tab'] == 'debug' ) {
wp_enqueue_style(
'wpo-wcpdf-jquery-ui-styles',
'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/smoothness/jquery-ui.css'
);
wp_enqueue_script( 'jquery-ui-datepicker' );
wp_enqueue_style(
'wpo-wcpdf-debug-tools-styles',
WPO_WCPDF()->plugin_url() . '/assets/css/debug-tools'.$suffix.'.css',
WPO_WCPDF_VERSION
);
wp_enqueue_script(
'wpo-wcpdf-debug',
WPO_WCPDF()->plugin_url() . '/assets/js/debug-script'.$suffix.'.js',
array( 'jquery', 'jquery-blockui', 'jquery-ui-datepicker' ),
WPO_WCPDF_VERSION
);
wp_localize_script(
'wpo-wcpdf-debug',
'wpo_wcpdf_debug',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'wpo_wcpdf_debug_nonce' ),
'download_label' => __( 'Download', 'woocommerce-pdf-invoices-packing-slips' ),
'confirm_reset' => __( 'Are you sure you want to reset this settings? This cannot be undone.', 'woocommerce-pdf-invoices-packing-slips' ),
'select_document_type' => __( 'Please select a document type', 'woocommerce-pdf-invoices-packing-slips' ),
'danger_zone' => array(
'enabled' => isset( WPO_WCPDF()->settings->debug_settings['enable_danger_zone_tools'] ) ? true : false,
'message' => sprintf(
/* translators: <a> tags */
__( '<strong>Enabled</strong>: %sclick here%s to start using the tools.', 'woocommerce-pdf-invoices-packing-slips' ),
'<a href="' . esc_url( add_query_arg( 'section', 'tools' ) ) . '#danger_zone">',
'</a>'
),
),
)
);
}
}
}
endif; // class_exists

View File

@@ -0,0 +1,123 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents' ) ) :
class Documents {
/** @var array Array of document classes */
public $documents = array();
/** @var Documents The single instance of the class */
protected static $_instance = null;
/**
* Main Documents Instance.
*
* Ensures only one instance of Documents is loaded or can be loaded.
*
* @since 2.0
* @static
* @return Documents Main instance
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Constructor for the document class hooks in all documents that can be created.
*
*/
public function __construct() {
add_action( 'init', array( $this, 'init' ), 15 ); // after regular 10 actions but before most 'follow-up' actions (usually 20+)
}
/**
* Init document classes.
*/
public function init() {
// Load Invoice & Packing Slip
$this->documents['\WPO\WC\PDF_Invoices\Documents\Invoice'] = new \WPO\WC\PDF_Invoices\Documents\Invoice();
$this->documents['\WPO\WC\PDF_Invoices\Documents\Packing_Slip'] = new \WPO\WC\PDF_Invoices\Documents\Packing_Slip();
// Allow plugins to add their own documents
$this->documents = apply_filters( 'wpo_wcpdf_document_classes', $this->documents );
do_action( 'wpo_wcpdf_init_documents' );
}
/**
* Return the document classes - used in admin to load settings.
*
* @param $filter
* @param $output_format Can be 'pdf', 'ubl' or anything for all
*
* @return array
*/
public function get_documents( $filter = 'enabled', $output_format = 'pdf' ) {
if ( empty( $this->documents ) ) {
$this->init();
}
// enabled
if ( 'enabled' === $filter && ! empty( $output_format ) ) {
$documents = array();
foreach ( $this->documents as $class_name => $document ) {
switch ( $output_format ) {
case 'pdf':
case 'ubl':
if ( in_array( $output_format, $document->output_formats ) && is_callable( array( $document, 'is_enabled' ) ) && $document->is_enabled( $output_format ) ) {
$documents[$class_name] = $document;
}
break;
default:
foreach ( $document->output_formats as $document_output_format ) {
if ( is_callable( array( $document, 'is_enabled' ) ) && $document->is_enabled( $document_output_format ) ) {
$documents[$class_name] = $document;
break; // prevents adding the same document twice or more
}
}
break;
}
}
// enabled and disabled
} else {
$documents = $this->documents;
}
return apply_filters( 'wpo_wcpdf_get_documents', $documents, $filter, $output_format, $this );
}
public function get_document( $document_type, $order ) {
foreach ( $this->get_documents( 'all' ) as $class_name => $document ) {
if ( $document->get_type() == $document_type && class_exists( $class_name ) ) {
return new $class_name( $order );
}
}
return false;
}
public function get_document_titles() {
$documents = $this->get_documents();
$document_titles = array();
foreach ( $documents as $document ) {
$document_titles[ $document->get_type() ] = $document->get_title();
}
return $document_titles;
}
}
endif; // class_exists

View File

@@ -0,0 +1,220 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Endpoint' ) ) :
class Endpoint {
public $action_suffix = '_wpo_wcpdf';
public $events = array( 'generate', 'printed' );
public $actions;
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
if ( $this->pretty_links_enabled() ) {
add_action( 'init', array( $this, 'add_endpoint' ) );
add_action( 'query_vars', array( $this, 'add_query_vars' ) );
add_action( 'parse_request', array( $this, 'handle_document_requests' ) );
}
$this->actions = $this->get_actions();
}
public function get_actions() {
$actions = [];
foreach ( $this->events as $event ) {
$actions[ $event ] = $event . $this->action_suffix;
}
return $actions;
}
public function pretty_links_enabled() {
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
if ( isset( $debug_settings['pretty_document_links'] ) ) {
return true;
} else {
return false;
}
}
public function get_identifier() {
return apply_filters( 'wpo_wcpdf_pretty_document_link_identifier', 'wcpdf' );
}
public function add_endpoint() {
add_rewrite_rule(
'^' . $this->get_identifier() . '/([^/]*)/([^/]*)/([^/]*)/([^/]*)?',
'index.php?action=' . $this->actions['generate'] . '&document_type=$matches[1]&order_ids=$matches[2]&access_key=$matches[3]&output=$matches[4]',
'top'
);
}
public function add_query_vars( $vars ) {
$vars[] = 'action';
$vars[] = 'document_type';
$vars[] = 'order_ids';
$vars[] = 'access_key';
$vars[] = 'output';
return $vars;
}
public function handle_document_requests() {
global $wp;
if ( ! empty( $wp->query_vars['action'] ) && $this->actions['generate'] == $wp->query_vars['action'] ) {
if ( ! empty( $wp->query_vars['document_type'] ) && ! empty( $wp->query_vars['order_ids'] ) && ! empty( $wp->query_vars['access_key'] ) && ! empty( $wp->query_vars['output'] ) ) {
$_REQUEST['action'] = $this->actions['generate'];
$_REQUEST['document_type'] = sanitize_text_field( $wp->query_vars['document_type'] );
$_REQUEST['order_ids'] = sanitize_text_field( $wp->query_vars['order_ids'] );
$_REQUEST['access_key'] = sanitize_text_field( $wp->query_vars['access_key'] );
$_REQUEST['output'] = sanitize_text_field( $wp->query_vars['output'] );
do_action( 'wp_ajax_' . $this->actions['generate'] );
}
}
}
public function get_document_link( $order, $document_type, $additional_vars = array() ) {
if ( empty( $order ) || empty( $document_type ) ) {
return '';
}
$access_type = $this->get_document_link_access_type();
switch ( $access_type ) {
case 'logged_in':
default:
$access_key = is_user_logged_in() ? wp_create_nonce( $this->actions['generate'] ) : '';
break;
case 'guest': // 'guest' is hybrid, it can behave as 'logged_in' if the user is logged in, but if not, behaves as 'full'
$access_key = ! is_user_logged_in() ? $order->get_order_key() : wp_create_nonce( $this->actions['generate'] );
break;
case 'full':
$access_key = $order->get_order_key();
break;
}
if ( empty( $access_key ) ) {
return '';
}
if ( $this->pretty_links_enabled() ) {
$output = isset( $additional_vars['output'] ) ? esc_attr( $additional_vars['output'] ) : 'pdf';
$parameters = array(
$this->get_identifier(),
$document_type,
$order->get_id(),
$access_key,
$output
);
$document_link = trailingslashit( get_home_url() ) . implode( '/', $parameters );
} else {
$document_link = add_query_arg( array(
'action' => $this->actions['generate'],
'document_type' => $document_type,
'order_ids' => $order->get_id(),
'access_key' => $access_key,
), admin_url( 'admin-ajax.php' ) );
}
// handle additional query vars
$additional_vars = apply_filters( 'wpo_wcpdf_document_link_additional_vars', $additional_vars, $order, $document_type );
if ( ! empty( $additional_vars ) && is_array( $additional_vars ) ) {
if ( isset( $additional_vars['output'] ) && $this->pretty_links_enabled() ) {
unset( $additional_vars['output'] );
}
$document_link = add_query_arg( $additional_vars, $document_link );
}
return esc_url( $document_link );
}
/**
* Get mark/unmark document printed link
*
* @param string $event Can be 'mark' or 'unmark'
* @param object $order
* @param string $document_type
* @param string $trigger
* @return void
*/
public function get_document_printed_link( $event, $order, $document_type, $trigger = 'manually' ) {
if ( empty( $event ) || ! in_array( $event, [ 'mark', 'unmark' ] ) ) {
return '';
}
if ( empty( $order ) || empty( $document_type ) || ! is_admin() ) {
return '';
}
$printed_link = add_query_arg( array(
'action' => $this->actions['printed'],
'event' => $event,
'document_type' => $document_type,
'order_id' => $order->get_id(),
'trigger' => $trigger,
'security' => wp_create_nonce( $this->actions['printed'] ),
), admin_url( 'admin-ajax.php' ) );
return esc_url( $printed_link );
}
/**
* Get document link access type from debug settings
*
* @return string
*/
public function get_document_link_access_type() {
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
$access_type = isset( $debug_settings['document_link_access_type'] ) ? $debug_settings['document_link_access_type'] : 'logged_in';
return apply_filters( 'wpo_wcpdf_document_link_access_type', $access_type, $this );
}
/**
* Get document denied frontend redirect URL
*
* @return string
*/
public function get_document_denied_frontend_redirect_url() {
$redirect_url = '';
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
if ( isset( $debug_settings['document_access_denied_redirect_page'] ) ) {
switch ( $debug_settings['document_access_denied_redirect_page'] ) {
case 'login_page':
$redirect_url = wp_sanitize_redirect( wp_login_url() );
break;
case 'myaccount_page':
$redirect_url = wp_sanitize_redirect( wc_get_page_permalink( 'myaccount' ) );
break;
case 'custom_page':
if ( isset( $debug_settings['document_custom_redirect_page'] ) && ! empty( $debug_settings['document_custom_redirect_page'] ) ) {
$redirect_url = wp_sanitize_redirect( $debug_settings['document_custom_redirect_page'] );
}
break;
case 'blank_page':
default:
break;
}
}
return apply_filters( 'wpo_wcpdf_document_denied_frontend_redirect_url', $redirect_url, $debug_settings, $this );
}
}
endif; // class_exists

View File

@@ -0,0 +1,233 @@
<?php
namespace WPO\WC\PDF_Invoices;
use Dompdf\Dompdf;
use Dompdf\Options;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Font_Synchronizer' ) ) :
class Font_Synchronizer {
/**
* Filename for the dompdf 'font cache'
*
* @var string
*/
public $font_cache_filename = "installed-fonts.json";
/**
* Vanilla instance of dompdf
*
* @var \Dompdf\Dompdf
*/
public $dompdf;
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Constructor
*/
public function __construct() {
$this->dompdf = new Dompdf();
}
/**
* Synchronize/update local fonts with plugin fonts, removing duplicates of the dompdf fonts
*
* @param string $destination path to the local fonts
* @return void
*/
public function sync( $destination, $merge_with_local = true ) {
$destination = trailingslashit( wp_normalize_path( $destination ) );
$plugin_fonts = $this->get_plugin_fonts();
$dompdf_fonts = $this->get_dompdf_fonts();
if ( $merge_with_local ) {
$local_fonts = $this->get_local_fonts( $destination );
} else {
$local_fonts = array();
}
// we always load dompdf fonts directly from the vendor folder, so delete local copies
foreach( $dompdf_fonts as $font_name => $filenames ) {
if ( array_key_exists( $font_name, $local_fonts ) ) {
$this->delete_font_files( $local_fonts[$font_name] );
unset( $local_fonts[$font_name] );
}
}
// update / add plugin fonts in local folder
foreach( $plugin_fonts as $font_name => $filenames ) {
$plugin_filenames = array_map( function( $file ){
return WPO_WCPDF()->plugin_path() . '/assets/fonts/' . $file;
}, $filenames );
$local_filenames = $this->copy_font_files( $plugin_filenames, $destination );
$local_fonts[$font_name] = $local_filenames;
}
// normalize one last time
$local_fonts = $this->normalize_font_paths( $local_fonts );
// rebuild font cache file
$cacheData = json_encode( $local_fonts, JSON_PRETTY_PRINT );
// write file with merged cache data
file_put_contents( $destination . $this->font_cache_filename, $cacheData );
}
/**
* Delete an array of files with all known extensions
*
* @param array $filenames array of filenames without the extension
* @return void
*/
public function delete_font_files( $filenames ) {
$plugin_folder = wp_normalize_path( WPO_WCPDF()->plugin_path() );
$extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm', '.afm.php' );
foreach ( $filenames as $filename ) {
// never delete files in our own plugin folder
if ( ! empty( $filename ) && false !== strpos( $filename, $plugin_folder ) ) {
continue;
}
foreach ( $extensions as $extension ) {
$file = $filename . $extension;
if ( file_exists( $file ) ) {
@unlink( $file );
}
}
}
}
/**
* Copy font files
*
* @param array $filenames array of filenames without the extension
* @param string $destination path to the local fonts
* @return array
*/
public function copy_font_files( $filenames, $destination ) {
$destination = trailingslashit( $destination );
$extensions = array( '.ttf', '.ufm', '.afm' );
$local_filenames = array();
foreach ( $filenames as $variant => $filename ) {
foreach ( $extensions as $extension ) {
$file = $filename . $extension;
if ( is_readable( $file ) ) {
$local_filename = $destination . basename( $file );
copy( $file, $local_filename );
}
}
$local_filenames[$variant] = $destination . basename( $filename );
}
return $local_filenames;
}
/**
* Get an array of all known local fonts (stored in the cache file)
*
* @param string $path path to the local fonts
* @return array
*/
public function get_local_fonts( $path ) {
// prepare variables used in the cache list
$fontDir = $path;
$rootDir = $this->dompdf->getOptions()->getRootDir();
$cache_file = trailingslashit( $path ) . $this->font_cache_filename;
$legacy_cache_file = trailingslashit( $path ) . 'dompdf_font_family_cache.php'; // Dompdf <2.0
if ( is_readable( $cache_file ) ) {
$json_data = file_get_contents( $cache_file );
$font_data = json_decode( $json_data, true );
} elseif ( is_readable( $legacy_cache_file ) ) {
$font_data = include $legacy_cache_file;
@unlink( $legacy_cache_file );
} else {
$font_data = array();
}
// if include fails it returns false - we'll log an error in that case
if ( $font_data === false ) {
wcpdf_log_error( sprintf( "Could not read font cache file (%s)", $cache_file ), 'critical' );
}
// dompdf 1.1.X uses a closure to return the fonts, instead of a plain array (1.0.X and older)
if ( ! is_array( $font_data ) && is_callable( $font_data ) ) {
$font_data = $font_data( $fontDir, $rootDir );
}
return is_array( $font_data ) ? $this->normalize_font_paths( $font_data ) : array();
}
/**
* Get all fonts included in dompdf
*
* @return array
*/
public function get_dompdf_fonts() {
$fonts = $this->dompdf->getFontMetrics()->getFontFamilies();
return $this->normalize_font_paths( $fonts );
}
/**
* Get all fonts from the plugin (excluding base path!)
*
* @return array
*/
public function get_plugin_fonts() {
return array (
'open sans' => array (
'normal' => 'OpenSans-Normal',
'bold' => 'OpenSans-Bold',
'italic' => 'OpenSans-Italic',
'bold_italic' => 'OpenSans-BoldItalic',
),
'segoe' => array (
'normal' => 'Segoe-Normal',
'bold' => 'Segoe-Bold',
'italic' => 'Segoe-Italic',
'bold_italic' => 'Segoe-BoldItalic',
),
'roboto slab' => array (
'normal' => 'RobotoSlab-Normal',
'bold' => 'RobotoSlab-Bold',
'italic' => 'RobotoSlab-Italic',
'bold_italic' => 'RobotoSlab-BoldItalic',
),
'currencies' => array (
'normal' => 'currencies',
'bold' => 'currencies',
'italic' => 'currencies',
'bold_italic' => 'currencies',
),
);
}
/**
* Apply path normalization to a font list
*
* @param array $fonts array of font entries
* @return array Normalized array of font entries
*/
public function normalize_font_paths( $fonts ) {
foreach( $fonts as $font_name => $filenames ) {
if ( ! is_array( $filenames ) ) {
continue;
}
foreach ( $filenames as $variant => $filename ) {
$fonts[$font_name][$variant] = wp_normalize_path( $filename );
}
}
return $fonts;
}
}
endif; // class_exists

View File

@@ -0,0 +1,207 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Frontend' ) ) :
class Frontend {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
add_filter( 'woocommerce_my_account_my_orders_actions', array( $this, 'my_account_pdf_link' ), 999, 2 ); // needs to be triggered later because of Jetpack query string: https://github.com/Automattic/jetpack/blob/1a062c5388083c7f15b9a3e82e61fde838e83047/projects/plugins/jetpack/modules/woocommerce-analytics/classes/class-jetpack-woocommerce-analytics-my-account.php#L235
add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_number' ), 10, 2 );
add_action( 'wp_enqueue_scripts', array( $this, 'open_my_account_pdf_link_on_new_tab' ), 999 );
add_shortcode( 'wcpdf_download_invoice', array( $this, 'generate_document_shortcode' ) );
add_shortcode( 'wcpdf_download_pdf', array( $this, 'generate_document_shortcode' ) );
add_shortcode( 'wcpdf_document_link', array( $this, 'generate_document_shortcode' ) );
}
/**
* Display download link on My Account page
*/
public function my_account_pdf_link( $actions, $order ) {
$this->disable_storing_document_settings();
$invoice = wcpdf_get_invoice( $order );
if ( $invoice && $invoice->is_enabled() ) {
$pdf_url = WPO_WCPDF()->endpoint->get_document_link( $order, 'invoice', array( 'my-account' => 'true' ) );
// check my account button settings
$button_setting = $invoice->get_setting( 'my_account_buttons', 'available' );
switch ( $button_setting ) {
case 'available':
$invoice_allowed = $invoice->exists();
break;
case 'always':
$invoice_allowed = true;
break;
case 'never':
$invoice_allowed = false;
break;
case 'custom':
$allowed_statuses = $button_setting = $invoice->get_setting( 'my_account_restrict', array() );
if ( !empty( $allowed_statuses ) && in_array( $order->get_status(), array_keys( $allowed_statuses ) ) ) {
$invoice_allowed = true;
} else {
$invoice_allowed = false;
}
break;
}
// Check if invoice has been created already or if status allows download (filter your own array of allowed statuses)
if ( $invoice_allowed || in_array( $order->get_status(), apply_filters( 'wpo_wcpdf_myaccount_allowed_order_statuses', array() ) ) ) {
$actions['invoice'] = array(
'url' => esc_url( $pdf_url ),
'name' => apply_filters( 'wpo_wcpdf_myaccount_button_text', $invoice->get_title(), $invoice )
);
}
}
return apply_filters( 'wpo_wcpdf_myaccount_actions', $actions, $order );
}
/**
* Open PDF on My Account page in a new browser tab/window
*/
public function open_my_account_pdf_link_on_new_tab() {
if ( function_exists( 'is_account_page' ) && is_account_page() ) {
if ( $general_settings = get_option( 'wpo_wcpdf_settings_general' ) ) {
if ( isset( $general_settings['download_display'] ) && $general_settings['download_display'] == 'display' ) {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
if ( function_exists( 'file_get_contents' ) && $script = file_get_contents( WPO_WCPDF()->plugin_path() . '/assets/js/my-account-link'.$suffix.'.js' ) ) {
if ( WPO_WCPDF()->endpoint->pretty_links_enabled() ) {
$script = str_replace( 'generate_wpo_wcpdf', WPO_WCPDF()->endpoint->get_identifier(), $script );
}
wp_add_inline_script( 'jquery', $script );
}
}
}
}
}
/**
* Add invoice number to WC REST API
*/
public function woocommerce_api_invoice_number ( $data, $order ) {
$this->disable_storing_document_settings();
$data['wpo_wcpdf_invoice_number'] = '';
if ( $invoice = wcpdf_get_invoice( $order ) ) {
$invoice_number = $invoice->get_number();
if ( !empty( $invoice_number ) ) {
$data['wpo_wcpdf_invoice_number'] = $invoice_number->get_formatted();
}
}
$this->restore_storing_document_settings();
return $data;
}
public function generate_document_shortcode( $atts, $content = null, $shortcode_tag = '' ) {
global $wp;
if ( is_admin() ) {
return;
}
// Default values
$values = shortcode_atts( array(
'order_id' => '',
'link_text' => '',
'id' => '',
'class' => 'wpo_wcpdf_document_link',
'document_type' => 'invoice',
), $atts );
$is_document_type_valid = false;
$documents = WPO_WCPDF()->documents->get_documents();
foreach ( $documents as $document ) {
if ( $document->get_type() === $values['document_type'] ) {
$is_document_type_valid = true;
if ( ! empty( $values['link_text'] ) ) {
$link_text = $values['link_text'];
} else {
$link_text = sprintf(
/* translators: %s: Document type */
__( 'Download %s (PDF)', 'woocommerce-pdf-invoices-packing-slips' ),
wp_kses_post( $document->get_type() )
);
}
break;
}
}
if ( ! $is_document_type_valid ) {
return;
}
// Get $order
if ( empty( $values['order_id'] ) ) {
if ( is_checkout() && is_wc_endpoint_url( 'order-received' ) && isset( $wp->query_vars['order-received'] ) ) {
$order = wc_get_order( $wp->query_vars['order-received'] );
} elseif ( is_account_page() && is_wc_endpoint_url( 'view-order' ) && isset( $wp->query_vars['view-order'] ) ) {
$order = wc_get_order( $wp->query_vars['view-order'] );
}
} else {
$order = wc_get_order( $values['order_id'] );
}
if ( empty( $order ) || ! is_object( $order ) ) {
return;
}
$document = wcpdf_get_document( $values['document_type'], $order );
if ( ! $document || ! $document->is_allowed() ) {
return;
}
$pdf_url = WPO_WCPDF()->endpoint->get_document_link( $order, $values['document_type'], [ 'shortcode' => 'true' ] );
if ( 'wcpdf_document_link' === $shortcode_tag ) {
return esc_url( $pdf_url );
}
return sprintf(
'<p><a %s class="%s" href="%s" target="_blank">%s</a></p>',
( ! empty( $values['id'] ) ? 'id="' . esc_attr( $values['id'] ) . '"' : '' ),
esc_attr( $values['class'] ),
esc_url( $pdf_url ),
esc_html( $link_text )
);
}
/**
* Document objects are created in order to check for existence and retrieve data,
* but we don't want to store the settings for uninitialized documents.
* Only use in frontend/backed (page requests), otherwise settings will never be stored!
*/
public function disable_storing_document_settings() {
add_filter( 'wpo_wcpdf_document_store_settings', array( $this, 'return_false' ), 9999 );
}
public function restore_storing_document_settings() {
remove_filter( 'wpo_wcpdf_document_store_settings', array( $this, 'return_false' ), 9999 );
}
public function return_false(){
return false;
}
}
endif; // class_exists

View File

@@ -0,0 +1,569 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Install' ) ) :
class Install {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
// run lifecycle methods
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
add_action( 'wp_loaded', array( $this, 'do_install' ) );
}
}
/** Lifecycle methods *******************************************************
* Because register_activation_hook only runs when the plugin is manually
* activated by the user, we're checking the current version against the
* version stored in the database
****************************************************************************/
/**
* Handles version checking
*/
public function do_install() {
// only install when woocommerce is active
if ( ! WPO_WCPDF()->is_woocommerce_activated() ) {
return;
}
$version_setting = 'wpo_wcpdf_version';
$installed_version = get_option( $version_setting );
// installed version lower than plugin version?
if ( version_compare( $installed_version, WPO_WCPDF_VERSION, '<' ) ) {
if ( ! $installed_version ) {
try {
$this->install();
} catch ( \Throwable $th ) {
wcpdf_log_error( sprintf( "Plugin install procedure failed (version %s): %s", WPO_WCPDF_VERSION, $th->getMessage() ), 'critical', $th );
}
} else {
try {
$this->upgrade( $installed_version );
} catch ( \Throwable $th ) {
wcpdf_log_error( sprintf( "Plugin upgrade procedure failed (updating from version %s to %s): %s", $installed_version, WPO_WCPDF_VERSION, $th->getMessage() ), 'critical', $th );
}
}
// new version number
update_option( $version_setting, WPO_WCPDF_VERSION );
} elseif ( $installed_version && version_compare( $installed_version, WPO_WCPDF_VERSION, '>' ) ) {
try {
$this->downgrade( $installed_version );
} catch ( \Throwable $th ) {
wcpdf_log_error( sprintf( "Plugin downgrade procedure failed (downgrading from version %s to %s): %s", $installed_version, WPO_WCPDF_VERSION, $th->getMessage() ), 'critical', $th );
}
// downgrade version number
update_option( $version_setting, WPO_WCPDF_VERSION );
}
// deactivate legacy addons
add_action( 'admin_init', array( WPO_WCPDF(), 'deactivate_legacy_addons') );
}
/**
* Plugin install method. Perform any installation tasks here
*/
protected function install() {
// only install when php 5.6 or higher
if ( version_compare( PHP_VERSION, '5.6', '<' ) ) {
return;
}
// check if upgrading from versionless (1.4.14 and older)
if ( get_option('wpo_wcpdf_general_settings') ) {
$this->upgrade( 'versionless' );
return;
}
// Get tmp folders
$tmp_base = WPO_WCPDF()->main->get_tmp_base();
// check if tmp folder exists => if not, initialize
if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) ) {
WPO_WCPDF()->main->init_tmp();
}
// Unsupported currency symbols
$unsupported_symbols = array (
'AED',
'AFN',
'BDT',
'BHD',
'BTC',
'CRC',
'DZD',
'GEL',
'GHS',
'ILS',
'INR',
'IQD',
'IRR',
'IRT',
'JOD',
'KHR',
'KPW',
'KRW',
'KWD',
'LAK',
'LBP',
'LKR',
'LYD',
'MAD',
'MNT',
'MUR',
'MVR',
'NPR',
'OMR',
'PHP',
'PKR',
'PYG',
'QAR',
'RUB',
'SAR',
'SCR',
'SDG',
'SYP',
'THB',
'TND',
'TRY',
'UAH',
'YER',
);
// set default settings
$settings_defaults = array(
'wpo_wcpdf_settings_general' => array(
'download_display' => 'display',
'template_path' => WPO_WCPDF()->plugin_path() . '/templates/Simple',
'currency_font' => ( in_array( get_woocommerce_currency(), $unsupported_symbols ) ) ? 1 : '',
'paper_size' => 'a4',
// 'header_logo' => '',
// 'shop_name' => array(),
// 'shop_address' => array(),
// 'footer' => array(),
// 'extra_1' => array(),
// 'extra_2' => array(),
// 'extra_3' => array(),
),
'wpo_wcpdf_documents_settings_invoice' => array(
'enabled' => 1,
// 'attach_to_email_ids' => array(),
// 'display_shipping_address' => '',
// 'display_email' => '',
// 'display_phone' => '',
// 'display_date' => '',
// 'display_number' => '',
// 'number_format' => array(),
// 'reset_number_yearly' => '',
// 'my_account_buttons' => '',
// 'invoice_number_column' => '',
// 'invoice_date_column' => '',
// 'disable_free' => '',
),
'wpo_wcpdf_documents_settings_packing-slip' => array(
'enabled' => 1,
// 'display_billing_address' => '',
// 'display_email' => '',
// 'display_phone' => '',
),
'wpo_wcpdf_settings_debug' => array(
// 'legacy_mode' => '',
// 'enable_debug' => '',
// 'html_output' => '',
// 'html_output' => '',
'enable_cleanup' => 1,
'cleanup_days' => 7,
),
);
foreach ($settings_defaults as $option => $defaults) {
add_option( $option, $defaults );
}
// set transient for wizard notification
set_transient( 'wpo_wcpdf_new_install', 'yes', DAY_IN_SECONDS * 2 );
// schedule the yearly reset number action
if ( ! empty( WPO_WCPDF()->settings ) && is_callable( array( WPO_WCPDF()->settings, 'schedule_yearly_reset_numbers' ) ) ) {
WPO_WCPDF()->settings->schedule_yearly_reset_numbers();
}
}
/**
* Plugin upgrade method. Perform any required upgrades here
*
* @param string $installed_version the currently installed ('old') version
*/
protected function upgrade( $installed_version ) {
// only upgrade when php 5.6 or higher
if ( version_compare( PHP_VERSION, '5.6', '<' ) ) {
return;
}
// sync fonts on every upgrade!
$tmp_base = WPO_WCPDF()->main->get_tmp_base();
// get fonts folder path
$font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
// check if tmp folder exists => if not, initialize
if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) || ! @is_dir( $font_path ) || ! wp_is_writable( $font_path ) ) {
WPO_WCPDF()->main->init_tmp();
} else {
// don't try merging fonts with local when updating pre 2.0
$pre_2 = ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) );
$merge_with_local = !$pre_2;
WPO_WCPDF()->main->copy_fonts( $font_path, $merge_with_local );
}
// to ensure fonts will be copied to the upload directory
delete_transient( 'wpo_wcpdf_subfolder_fonts_has_files' );
// 1.5.28 update: copy next invoice number to separate setting
if ( $installed_version == 'versionless' || version_compare( $installed_version, '1.5.28', '<' ) ) {
$template_settings = get_option( 'wpo_wcpdf_template_settings' );
$next_invoice_number = isset($template_settings['next_invoice_number'])?$template_settings['next_invoice_number']:'';
update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
}
// 2.0-dev update: reorganize settings
if ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) ) {
$old_settings = array(
'wpo_wcpdf_general_settings' => get_option( 'wpo_wcpdf_general_settings' ),
'wpo_wcpdf_template_settings' => get_option( 'wpo_wcpdf_template_settings' ),
'wpo_wcpdf_debug_settings' => get_option( 'wpo_wcpdf_debug_settings' ),
);
// combine invoice number formatting in array
$old_settings['wpo_wcpdf_template_settings']['invoice_number_formatting'] = array();
$format_option_keys = array('padding','suffix','prefix');
foreach ($format_option_keys as $format_option_key) {
if (isset($old_settings['wpo_wcpdf_template_settings']["invoice_number_formatting_{$format_option_key}"])) {
$old_settings['wpo_wcpdf_template_settings']['invoice_number_formatting'][$format_option_key] = $old_settings['wpo_wcpdf_template_settings']["invoice_number_formatting_{$format_option_key}"];
}
}
// convert abbreviated email_ids
if (isset($old_settings['wpo_wcpdf_general_settings']['email_pdf'])) {
foreach ($old_settings['wpo_wcpdf_general_settings']['email_pdf'] as $email_id => $value) {
if ($email_id == 'completed' || $email_id == 'processing') {
$old_settings['wpo_wcpdf_general_settings']['email_pdf']["customer_{$email_id}_order"] = $value;
unset($old_settings['wpo_wcpdf_general_settings']['email_pdf'][$email_id]);
}
}
}
// Migrate template path
// forward slash for consistency/compatibility
if ( ! empty( $old_settings['wpo_wcpdf_template_settings']['template_path'] ) ) {
$template_path = str_replace( '\\', '/', $old_settings['wpo_wcpdf_template_settings']['template_path'] );
// strip abspath (forward slashed) if included
$template_path = str_replace( str_replace('\\','/', ABSPATH), '', $template_path );
// strip pdf subfolder from templates path
$template_path = str_replace( '/templates/pdf/', '/templates/', $template_path );
$old_settings['wpo_wcpdf_template_settings']['template_path'] = $template_path;
}
// map new settings to old
$settings_map = array(
'wpo_wcpdf_settings_general' => array(
'download_display' => array( 'wpo_wcpdf_general_settings' => 'download_display' ),
'template_path' => array( 'wpo_wcpdf_template_settings' => 'template_path' ),
'currency_font' => array( 'wpo_wcpdf_template_settings' => 'currency_font' ),
'paper_size' => array( 'wpo_wcpdf_template_settings' => 'paper_size' ),
'header_logo' => array( 'wpo_wcpdf_template_settings' => 'header_logo' ),
'shop_name' => array( 'wpo_wcpdf_template_settings' => 'shop_name' ),
'shop_address' => array( 'wpo_wcpdf_template_settings' => 'shop_address' ),
'footer' => array( 'wpo_wcpdf_template_settings' => 'footer' ),
'extra_1' => array( 'wpo_wcpdf_template_settings' => 'extra_1' ),
'extra_2' => array( 'wpo_wcpdf_template_settings' => 'extra_2' ),
'extra_3' => array( 'wpo_wcpdf_template_settings' => 'extra_3' ),
),
'wpo_wcpdf_documents_settings_invoice' => array(
'attach_to_email_ids' => array( 'wpo_wcpdf_general_settings' => 'email_pdf' ),
'display_shipping_address' => array( 'wpo_wcpdf_template_settings' => 'invoice_shipping_address' ),
'display_email' => array( 'wpo_wcpdf_template_settings' => 'invoice_email' ),
'display_phone' => array( 'wpo_wcpdf_template_settings' => 'invoice_phone' ),
'display_date' => array( 'wpo_wcpdf_template_settings' => 'display_date' ),
'display_number' => array( 'wpo_wcpdf_template_settings' => 'display_number' ),
'number_format' => array( 'wpo_wcpdf_template_settings' => 'invoice_number_formatting' ),
'reset_number_yearly' => array( 'wpo_wcpdf_template_settings' => 'yearly_reset_invoice_number' ),
'my_account_buttons' => array( 'wpo_wcpdf_general_settings' => 'my_account_buttons' ),
'invoice_number_column' => array( 'wpo_wcpdf_general_settings' => 'invoice_number_column' ),
'invoice_date_column' => array( 'wpo_wcpdf_general_settings' => 'invoice_date_column' ),
'disable_free' => array( 'wpo_wcpdf_general_settings' => 'disable_free' ),
),
'wpo_wcpdf_documents_settings_packing-slip' => array(
'display_billing_address' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_billing_address' ),
'display_email' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_email' ),
'display_phone' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_phone' ),
),
'wpo_wcpdf_settings_debug' => array(
'enable_debug' => array( 'wpo_wcpdf_debug_settings' => 'enable_debug' ),
'html_output' => array( 'wpo_wcpdf_debug_settings' => 'html_output' ),
),
);
// walk through map
foreach ($settings_map as $new_option => $new_settings_keys) {
${$new_option} = array();
foreach ($new_settings_keys as $new_key => $old_setting ) {
$old_key = reset($old_setting);
$old_option = key($old_setting);
if (!empty($old_settings[$old_option][$old_key])) {
// turn translatable fields into array
$translatable_fields = array('shop_name','shop_address','footer','extra_1','extra_2','extra_3');
if (in_array($new_key, $translatable_fields)) {
${$new_option}[$new_key] = array( 'default' => $old_settings[$old_option][$old_key] );
} else {
${$new_option}[$new_key] = $old_settings[$old_option][$old_key];
}
}
}
// auto enable invoice & packing slip
$enabled = array( 'wpo_wcpdf_documents_settings_invoice', 'wpo_wcpdf_documents_settings_packing-slip' );
if ( in_array( $new_option, $enabled ) ) {
${$new_option}['enabled'] = 1;
}
// merge with existing settings
${$new_option."_old"} = get_option( $new_option, ${$new_option} ); // second argument loads new as default in case the settings did not exist yet
${$new_option} = (array) ${$new_option} + (array) ${$new_option."_old"}; // duplicate options take new options as default
// store new option values
update_option( $new_option, ${$new_option} );
}
}
// 2.0-beta-2 update: copy next number to separate db store
if ( version_compare( $installed_version, '2.0-beta-2', '<' ) ) {
$next_number = get_option( 'wpo_wcpdf_next_invoice_number' );
if ( ! empty( $next_number ) ) {
$number_store = new \WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store( 'invoice_number' );
$number_store->set_next( (int) $next_number );
}
// we're not deleting this option yet to make downgrading possible
// delete_option( 'wpo_wcpdf_next_invoice_number' ); // clean up after ourselves
}
// 2.1.9: set cleanup defaults
if ( $installed_version == 'versionless' || version_compare( $installed_version, '2.1.9', '<' ) ) {
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
$debug_settings['enable_cleanup'] = 1;
$debug_settings['cleanup_days'] = 7;
update_option( 'wpo_wcpdf_settings_debug', $debug_settings );
}
// 2.10.0-dev: migrate template path to template ID
// 2.11.5: improvements to the migration procedure
if ( version_compare( $installed_version, '2.11.5', '<' ) ) {
if ( ! empty( WPO_WCPDF()->settings ) && is_callable( array( WPO_WCPDF()->settings, 'maybe_migrate_template_paths' ) ) ) {
WPO_WCPDF()->settings->maybe_migrate_template_paths();
}
}
// 2.11.2: remove the obsolete .dist font cache file and mustRead.html from local fonts folder
if ( version_compare( $installed_version, '2.11.2', '<' ) ) {
@unlink( trailingslashit( $font_path ) . 'dompdf_font_family_cache.dist.php' );
@unlink( trailingslashit( $font_path ) . 'mustRead.html' );
}
// 2.12.2-dev-1: change 'date' database table default value to '1000-01-01 00:00:00'
if ( version_compare( $installed_version, '2.12.2-dev-1', '<' ) ) {
global $wpdb;
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
$store_name = "{$document->slug}_number";
$method = WPO_WCPDF()->settings->get_sequential_number_store_method();
$table_name = apply_filters( "wpo_wcpdf_number_store_table_name", "{$wpdb->prefix}wcpdf_{$store_name}", $store_name, $method );
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ) != $table_name ) {
continue;
}
if ( is_callable( array( $document, 'get_sequential_number_store' ) ) ) {
$number_store = $document->get_sequential_number_store();
if ( ! empty( $number_store ) ) {
$column_name = 'date';
$query = $wpdb->query( "ALTER TABLE {$number_store->table_name} ALTER {$column_name} SET DEFAULT '1000-01-01 00:00:00'" );
if ( $query ) {
wcpdf_log_error(
"Default value changed for 'date' column to '1000-01-01 00:00:00' on database table: {$number_store->table_name}",
'info'
);
} else {
wcpdf_log_error(
"An error occurred! The default value for 'date' column couldn't be changed to '1000-01-01 00:00:00' on database table: {$number_store->table_name}",
'critical'
);
}
}
}
}
}
// 3.0.0-dev-1: remove saved option 'use_html5_parser'
if ( version_compare( $installed_version, '3.0.0-dev-1', '<' ) ) {
// removes 'HTML5 parser' setting value
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
if ( ! empty( $debug_settings['use_html5_parser'] ) ) {
unset( $debug_settings['use_html5_parser'] );
update_option( 'wpo_wcpdf_settings_debug', $debug_settings );
}
}
// 3.3.0-dev-1: schedule the yearly reset number action
if ( version_compare( $installed_version, '3.3.0-dev-1', '<' ) ) {
if ( ! empty( WPO_WCPDF()->settings ) && is_callable( array( WPO_WCPDF()->settings, 'schedule_yearly_reset_numbers' ) ) ) {
WPO_WCPDF()->settings->schedule_yearly_reset_numbers();
}
}
// 3.5.7-dev-1: migrate 'guest_access' setting to 'document_link_access_type'
if ( version_compare( $installed_version, '3.5.7-dev-1', '<' ) ) {
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
if ( ! empty( $debug_settings['guest_access'] ) ) {
unset( $debug_settings['guest_access'] );
$debug_settings['document_link_access_type'] = 'guest';
update_option( 'wpo_wcpdf_settings_debug', $debug_settings );
}
}
// 3.6.3-dev-1: check if 'legacy_mode' is enabled, and disable it
if ( version_compare( $installed_version, '3.6.3-dev-1', '<' ) ) {
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
$update = false;
if ( ! empty( $debug_settings['legacy_mode'] ) ) {
unset( $debug_settings['legacy_mode'] );
$update = true;
}
if ( ! empty( $debug_settings['legacy_textdomain'] ) ) {
unset( $debug_settings['legacy_textdomain'] );
$update = true;
}
if ( $update ) {
update_option( 'wpo_wcpdf_settings_debug', $debug_settings );
}
}
// 3.7.0-beta-4: deactivate legacy ubl addon and migrate settings
if ( version_compare( $installed_version, '3.7.0-beta-4', '<' ) ) {
// deactivate legacy ubl addon
WPO_WCPDF()->deactivate_ubl_addon();
// legacy ubl general/invoice settings
$legacy_ubl_general_settings = get_option( 'ubl_wc_general', [] );
$general_settings = get_option( 'wpo_wcpdf_settings_general', [] );
$invoice_ubl_settings = get_option( 'wpo_wcpdf_documents_settings_invoice_ubl', [] );
$settings_to_migrate = [
'vat_number' => 'general',
'coc_number' => 'general',
'company_name' => 'general', // corresponds to 'shop_name' in the General Settings
'attach_to_email_ids' => 'invoice_ubl',
'include_encrypted_pdf' => 'invoice_ubl',
];
foreach ( $settings_to_migrate as $setting => $type ) {
$update = [];
switch ( $type ) {
case 'general':
if ( isset( $legacy_ubl_general_settings[$setting] ) ) {
$legacy_ubl_setting_value = $legacy_ubl_general_settings[$setting];
$setting = ( 'company_name' === $setting && ! isset( $general_settings['shop_name'] ) ) ? 'shop_name' : $setting;
if ( 'company_name' !== $setting ) {
$general_settings[$setting] = $legacy_ubl_setting_value;
$update[] = $type;
}
}
break;
case 'invoice_ubl':
if ( isset( $legacy_ubl_general_settings[$setting] ) ) {
$invoice_ubl_settings[$setting] = $legacy_ubl_general_settings[$setting];
$update[] = $type;
}
break;
}
if ( ! empty( $update ) ) {
$update = array_unique( $update );
foreach ( $update as $type ) {
switch ( $type ) {
case 'general':
update_option( 'wpo_wcpdf_settings_general', $general_settings );
break;
case 'invoice_ubl':
$invoice_ubl_settings['enabled'] = '1';
update_option( 'wpo_wcpdf_documents_settings_invoice_ubl', $invoice_ubl_settings );
break;
}
}
}
}
// legacy ubl tax settings
$legacy_ubl_tax_setings = get_option( 'ubl_wc_taxes', [] );
if ( ! empty( $legacy_ubl_tax_setings ) ) {
update_option( 'wpo_wcpdf_settings_ubl_taxes', $legacy_ubl_tax_setings );
}
// set transient to flush rewrite rules if pretty links are enabled
if ( WPO_WCPDF()->endpoint->pretty_links_enabled() ) {
set_transient( 'wpo_wcpdf_flush_rewrite_rules', 'yes', HOUR_IN_SECONDS );
}
}
}
/**
* Plugin downgrade method. Perform any required downgrades here
*
*
* @param string $installed_version the currently installed ('old') version (actually higher since this is a downgrade)
*/
protected function downgrade( $installed_version ) {
// make sure fonts match with version: copy from plugin folder
$tmp_base = WPO_WCPDF()->main->get_tmp_base();
// make sure we have the fonts directory
$font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
// don't continue if we don't have an upload dir
if ($tmp_base === false) {
return false;
}
// check if tmp folder exists => if not, initialize
if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) || ! @is_dir( $font_path ) || ! wp_is_writable( $font_path ) ) {
WPO_WCPDF()->main->init_tmp();
} else {
WPO_WCPDF()->main->copy_fonts( $font_path );
}
}
}
endif; // class_exists

View File

@@ -0,0 +1,992 @@
<?php
namespace WPO\WC\PDF_Invoices;
use WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store;
use WPO\WC\PDF_Invoices\Updraft_Semaphore_3_0 as Semaphore;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings' ) ) :
class Settings {
public $options_page_hook;
public $callbacks;
public $general;
public $documents;
public $debug;
public $upgrade;
public $ubl;
public $general_settings;
public $debug_settings;
public $ubl_tax_settings;
public $lock_name;
public $lock_context;
public $lock_time;
public $lock_retries;
private $installed_templates = array();
private $installed_templates_cache = array();
private $template_list_cache = array();
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
$this->callbacks = \WPO\WC\PDF_Invoices\Settings\Settings_Callbacks::instance();
$this->general = \WPO\WC\PDF_Invoices\Settings\Settings_General::instance();
$this->documents = \WPO\WC\PDF_Invoices\Settings\Settings_Documents::instance();
$this->debug = \WPO\WC\PDF_Invoices\Settings\Settings_Debug::instance();
$this->ubl = \WPO\WC\PDF_Invoices\Settings\Settings_UBL::instance();
$this->upgrade = \WPO\WC\PDF_Invoices\Settings\Settings_Upgrade::instance();
$this->general_settings = get_option( 'wpo_wcpdf_settings_general' );
$this->debug_settings = get_option( 'wpo_wcpdf_settings_debug' );
$this->ubl_tax_settings = get_option( 'wpo_wcpdf_settings_ubl_taxes' );
$this->lock_name = 'wpo_wcpdf_semaphore_lock';
$this->lock_context = array( 'source' => 'wpo-wcpdf-semaphore' );
$this->lock_time = apply_filters( 'wpo_wcpdf_semaphore_lock_time', 2 );
$this->lock_retries = apply_filters( 'wpo_wcpdf_semaphore_lock_retries', 0 );
// Settings menu item
add_action( 'admin_menu', array( $this, 'menu' ), 999 ); // Add menu
// Links on plugin page
add_filter( 'plugin_action_links_'.WPO_WCPDF()->plugin_basename, array( $this, 'add_settings_link' ) );
add_filter( 'plugin_row_meta', array( $this, 'add_support_links' ), 10, 2 );
// settings capabilities
add_filter( 'option_page_capability_wpo_wcpdf_general_settings', array( $this, 'user_settings_capability' ) );
// admin notice for auto_increment_increment
// add_action( 'admin_notices', array( $this, 'check_auto_increment_increment') );
// AJAX set number store
add_action( 'wp_ajax_wpo_wcpdf_set_next_number', array( $this, 'set_number_store' ) );
// AJAX get header logo setting HTML
add_action( 'wp_ajax_wpo_wcpdf_get_media_upload_setting_html', array( $this, 'get_media_upload_setting_html' ) );
// refresh template path cache each time the general settings are updated
add_action( "update_option_wpo_wcpdf_settings_general", array( $this, 'general_settings_updated' ), 10, 3 );
// sets transient to flush rewrite rules
add_action( "update_option_wpo_wcpdf_settings_debug", array( $this, 'debug_settings_updated' ), 10, 3 );
add_action( 'init', array( $this, 'maybe_delete_flush_rewrite_rules_transient' ) );
// migrate old template paths to template IDs before loading settings page
add_action( 'wpo_wcpdf_settings_output_general', array( $this, 'maybe_migrate_template_paths' ), 9, 1 );
// AJAX preview
add_action( 'wp_ajax_wpo_wcpdf_preview', array( $this, 'ajax_preview' ) );
// AJAX preview order search
add_action( 'wp_ajax_wpo_wcpdf_preview_order_search', array( $this, 'preview_order_search' ) );
// schedule yearly reset numbers
add_action( 'wpo_wcpdf_schedule_yearly_reset_numbers', array( $this, 'yearly_reset_numbers' ) );
}
public function menu() {
$parent_slug = 'woocommerce';
$this->options_page_hook = add_submenu_page(
$parent_slug,
esc_html__( 'PDF Invoices', 'woocommerce-pdf-invoices-packing-slips' ),
esc_html__( 'PDF Invoices', 'woocommerce-pdf-invoices-packing-slips' ),
$this->user_settings_capability(),
'wpo_wcpdf_options_page',
array( $this, 'settings_page' )
);
}
/**
* Add settings link to plugins page
*/
public function add_settings_link( $links ) {
$action_links = array(
'settings' => '<a href="admin.php?page=wpo_wcpdf_options_page">'. esc_html__( 'Settings', 'woocommerce' ) . '</a>',
);
return array_merge( $action_links, $links );
}
/**
* Add various support links to plugin page
* after meta (version, authors, site)
*/
public function add_support_links( $links, $file ) {
if ( $file == WPO_WCPDF()->plugin_basename ) {
$row_meta = array(
'docs' => '<a href="https://docs.wpovernight.com/topic/woocommerce-pdf-invoices-packing-slips/" target="_blank" title="' . esc_html__( 'Documentation', 'woocommerce-pdf-invoices-packing-slips' ) . '">' . esc_html__( 'Documentation', 'woocommerce-pdf-invoices-packing-slips' ) . '</a>',
'support' => '<a href="https://wordpress.org/support/plugin/woocommerce-pdf-invoices-packing-slips" target="_blank" title="' . esc_html__( 'Support Forum', 'woocommerce-pdf-invoices-packing-slips' ) . '">' . esc_html__( 'Support Forum', 'woocommerce-pdf-invoices-packing-slips' ) . '</a>',
);
return array_merge( $links, $row_meta );
}
return (array) $links;
}
/**
* Get a valid user role settings capability.
* @return string
*/
public function user_settings_capability() {
$user_capability = 'manage_woocommerce';
$capabilities_to_check = apply_filters( 'wpo_wcpdf_settings_user_role_capabilities', array( $user_capability ) );
foreach ( $capabilities_to_check as $capability ) {
if ( current_user_can( $capability ) ) {
$user_capability = $capability;
break;
}
}
return $user_capability;
}
/**
* Check if user role can manage settings.
* @return bool
*/
public function user_can_manage_settings() {
return current_user_can( $this->user_settings_capability() );
}
function check_auto_increment_increment() {
global $wpdb;
$row = $wpdb->get_row( "SHOW VARIABLES LIKE 'auto_increment_increment'" );
if ( ! empty( $row ) && ! empty( $row->Value ) && $row->Value != 1 ) {
/* translators: database row value */
$error = wp_kses_post( sprintf( __( "<strong>Warning!</strong> Your database has an AUTO_INCREMENT step size of %d, your invoice numbers may not be sequential. Enable the 'Calculate document numbers (slow)' setting in the Advanced tab to use an alternate method." , 'woocommerce-pdf-invoices-packing-slips' ), intval( $row->Value ) ) );
printf( '<div class="error"><p>%s</p></div>', $error );
}
}
public function settings_page() {
// feedback on settings save
settings_errors();
$settings_tabs = apply_filters( 'wpo_wcpdf_settings_tabs', array(
'general' => array(
'title' => __( 'General', 'woocommerce-pdf-invoices-packing-slips' ),
'preview_states' => 3,
),
'documents' => array(
'title' => __( 'Documents', 'woocommerce-pdf-invoices-packing-slips' ),
'preview_states' => 3,
),
'ubl' => array(
'title' => __( 'UBL', 'woocommerce-pdf-invoices-packing-slips' ),
'preview_states' => 1,
'beta' => true,
),
) );
// add status and upgrade tabs last in row
$settings_tabs['debug'] = array(
'title' => __( 'Advanced', 'woocommerce-pdf-invoices-packing-slips' ),
'preview_states' => 1,
);
$settings_tabs['upgrade'] = array(
'title' => __( 'Upgrade', 'woocommerce-pdf-invoices-packing-slips' ),
'preview_states' => 1,
);
$settings_tabs = $this->maybe_disable_preview_on_settings_tabs( $settings_tabs ); // disable preview on debug setting
$default_tab = apply_filters( 'wpo_wcpdf_settings_tabs_default', ! empty( $settings_tabs['general'] ) ? 'general' : key( $settings_tabs ) );
$active_tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( $_GET[ 'tab' ] ) : $default_tab;
$active_section = isset( $_GET[ 'section' ] ) ? sanitize_text_field( $_GET[ 'section' ] ) : '';
include( 'views/settings-page.php' );
}
public function maybe_disable_preview_on_settings_tabs( $settings_tabs ) {
$debug_settings = get_option( 'wpo_wcpdf_settings_debug', array() );
$close_preview = isset( $debug_settings['disable_preview'] );
if ( $close_preview ) {
foreach ( $settings_tabs as $tab_key => &$tab ) {
if ( is_array( $tab ) && ! empty( $tab['preview_states'] ) ) {
$tab['preview_states'] = 1;
}
}
}
return $settings_tabs;
}
public function ajax_preview() {
check_ajax_referer( 'wpo_wcpdf_preview', 'security' );
try {
// check permissions
if ( ! $this->user_can_manage_settings() ) {
throw new \Exception( esc_html__( 'You do not have sufficient permissions to access this page.', 'woocommerce-pdf-invoices-packing-slips' ), 403 );
}
// get document type
if ( ! empty( $_POST['document_type'] ) ) {
$document_type = sanitize_text_field( $_POST['document_type'] );
} else {
$document_type = 'invoice';
}
// get order ID
if ( ! empty( $_POST['order_id'] ) ) {
$order_id = sanitize_text_field( $_POST['order_id'] );
if ( $document_type == 'credit-note' ) {
// get last refund ID of the order if available
$refund = wc_get_orders(
array(
'type' => 'shop_order_refund',
'parent' => $order_id,
'limit' => 1,
)
);
$order_id = ! empty( $refund ) ? $refund[0]->get_id() : $order_id;
}
} else {
// default to last order
$default_order_id = wc_get_orders( apply_filters( 'wpo_wcpdf_preview_default_order_id_query_args', array(
'limit' => 1,
'return' => 'ids',
'type' => 'shop_order',
), $document_type ) );
$order_id = apply_filters( 'wpo_wcpdf_preview_default_order_id', ! empty( $default_order_id ) ? reset( $default_order_id ) : false );
}
// get PDF data for preview
if ( $order_id ) {
$order = apply_filters( 'wpo_wcpdf_preview_order_object', wc_get_order( $order_id ), $order_id, $document_type );
if ( empty( $order ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'Order not found!', 'woocommerce-pdf-invoices-packing-slips' ) ) );
}
if ( ! in_array( $order->get_type(), array( 'shop_order', 'shop_order_refund' ) ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'Object found is not an order!', 'woocommerce-pdf-invoices-packing-slips' ) ) );
}
// process settings data
if ( ! empty( $_POST['data'] ) ) {
// parse form data
parse_str( $_POST['data'], $form_data );
$form_data = stripslashes_deep( $form_data );
foreach ( $form_data as $option_key => $form_settings ) {
if ( ! empty( $option_key ) && false === apply_filters( 'wpo_wcpdf_preview_filter_option', 0 === strpos( $option_key, 'wpo_wcpdf' ), $option_key ) ) {
continue; // not our business
}
// validate option values
$form_settings = $this->callbacks->validate( $form_settings );
// filter the options
add_filter( "option_{$option_key}", function( $value, $option ) use ( $form_settings ) {
return maybe_unserialize( $form_settings );
}, 99, 2 );
}
// reload settings
$this->general_settings = get_option( 'wpo_wcpdf_settings_general' );
$this->debug_settings = get_option( 'wpo_wcpdf_settings_debug' );
do_action( 'wpo_wcpdf_preview_after_reload_settings' );
}
$document = wcpdf_get_document( $document_type, $order );
if ( $document ) {
if ( ! $document->exists() ) {
$document->set_date( current_time( 'timestamp', true ) );
$number_store_method = $this->get_sequential_number_store_method();
$number_store_name = apply_filters( 'wpo_wcpdf_document_sequential_number_store', "{$document->slug}_number", $document );
$number_store = new Sequential_Number_Store( $number_store_name, $number_store_method );
$document->set_number( $number_store->get_next() );
}
// apply document number formatting
if ( $document_number = $document->get_number( $document->get_type() ) ) {
if ( ! empty( $document->settings['number_format'] ) ) {
foreach ( $document->settings['number_format'] as $key => $value ) {
$document_number->$key = $document->settings['number_format'][$key];
}
}
$document_number->apply_formatting( $document, $order );
}
// preview
$output_format = ( ! empty( $_REQUEST['output_format'] ) && $_REQUEST['output_format'] != 'pdf' && in_array( $_REQUEST['output_format'], $document->output_formats ) ) ? esc_attr( $_REQUEST['output_format'] ) : 'pdf';
switch ( $output_format ) {
default:
case 'pdf':
$preview_data = base64_encode( $document->preview_pdf() );
break;
case 'ubl':
$preview_data = $document->preview_ubl();
break;
}
wp_send_json_success( array(
'preview_data' => $preview_data,
'output_format' => $output_format,
) );
} else {
wp_send_json_error(
array(
'error' => sprintf(
/* translators: order ID */
esc_html__( 'Document not available for order #%s, try selecting a different order.', 'woocommerce-pdf-invoices-packing-slips' ),
$order_id
)
)
);
}
} else {
wp_send_json_error( array( 'error' => esc_html__( 'No WooCommerce orders found! Please consider adding your first order to see this preview.', 'woocommerce-pdf-invoices-packing-slips' ) ) );
}
} catch ( \Throwable $th ) {
wp_send_json_error(
array(
'error' => sprintf(
/* translators: error message */
esc_html__( 'Error trying to generate document: %s', 'woocommerce-pdf-invoices-packing-slips' ),
$th->getMessage()
)
)
);
}
wp_die();
}
public function preview_order_search() {
check_ajax_referer( 'wpo_wcpdf_preview', 'security' );
try {
// check permissions
if ( ! $this->user_can_manage_settings() ) {
throw new \Exception( esc_html__( 'You do not have sufficient permissions to access this page.', 'woocommerce-pdf-invoices-packing-slips' ), 403 );
}
if ( ! empty( $_POST['search'] ) && ! empty( $_POST['document_type'] ) ) {
$search = sanitize_text_field( $_POST['search'] );
$document_type = sanitize_text_field( $_POST['document_type'] );
$results = array();
// we have an order ID
if ( is_numeric( $search ) && wc_get_order( $search ) ) {
$results = [ $search ];
// no order ID, let's try with customer
} else {
$default_args = apply_filters( 'wpo_wcpdf_preview_order_search_args', array(
'type' => 'shop_order',
'limit' => 10,
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
), $document_type );
// search by email
if ( is_email( $search ) ) {
$args = array( 'customer' => $search );
$args = $args + $default_args;
$results = wc_get_orders( $args );
// search by names
} else {
$names = array( 'billing_first_name', 'billing_last_name', 'billing_company' );
foreach ( $names as $name ) {
$args = array( $name => $search );
$args = $args + $default_args;
$results = wc_get_orders( $args );
if ( count( $results ) > 0 ) {
break;
}
}
}
}
// filter results
$results = apply_filters( 'wpo_wcpdf_preview_order_search_results', $results, $search, $document_type );
// if we got here we have results!
if ( ! empty( $results ) ) {
$data = array();
foreach ( $results as $value ) {
$order = wc_get_order( $value );
if ( empty( $order ) ) {
continue;
}
$order_id = is_callable( array( $order, 'get_id' ) ) ? $order->get_id() : 0;
$data[$order_id]['order_number'] = is_callable( array( $order, 'get_order_number' ) ) ? $order->get_order_number() : '';
$data[$order_id]['billing_first_name'] = is_callable( array( $order, 'get_billing_first_name' ) ) ? $order->get_billing_first_name() : '';
$data[$order_id]['billing_last_name'] = is_callable( array( $order, 'get_billing_last_name' ) ) ? $order->get_billing_last_name() : '';
$data[$order_id]['billing_company'] = is_callable( array( $order, 'get_billing_company' ) ) ? $order->get_billing_company() : '';
$data[$order_id]['date_created'] = is_callable( array( $order, 'get_date_created' ) ) ? '<strong>' . esc_attr__( 'Date', 'woocommerce-pdf-invoices-packing-slips' ) . ':</strong> ' . $order->get_date_created()->format( 'Y/m/d' ) : '';
$data[$order_id]['total'] = is_callable( array( $order, 'get_total' ) ) ? '<strong>' . esc_attr__( 'Total', 'woocommerce-pdf-invoices-packing-slips' ) . ':</strong> ' . wc_price( $order->get_total() ) : '';
}
$data = apply_filters( 'wpo_wcpdf_preview_order_search_data', $data, $results );
wp_send_json_success( $data );
} else {
wp_send_json_error( array( 'error' => esc_html__( 'No order(s) found!', 'woocommerce-pdf-invoices-packing-slips' ) ) );
}
} else {
wp_send_json_error( array( 'error' => esc_html__( 'An error occurred when trying to process your request!', 'woocommerce-pdf-invoices-packing-slips' ) ) );
}
} catch ( \Throwable $th ) {
wp_send_json_error(
array(
'error' => sprintf(
/* translators: error message */
esc_html__( 'Error trying to get orders: %s', 'woocommerce-pdf-invoices-packing-slips' ),
$th->getMessage()
)
)
);
}
wp_die();
}
public function add_settings_fields( $settings_fields, $page, $option_group, $option_name ) {
foreach ( $settings_fields as $settings_field ) {
if ( ! isset( $settings_field['callback'] ) ) {
continue;
} elseif ( is_callable( array( $this->callbacks, $settings_field['callback'] ) ) ) {
$callback = array( $this->callbacks, $settings_field['callback'] );
} elseif ( is_callable( $settings_field['callback'] ) ) {
$callback = $settings_field['callback'];
} else {
continue;
}
if ( $settings_field['type'] == 'section' ) {
add_settings_section(
$settings_field['id'],
$settings_field['title'],
$callback,
$page
);
} else {
add_settings_field(
$settings_field['id'],
$settings_field['title'],
$callback,
$page,
$settings_field['section'],
$settings_field['args']
);
// register option separately for singular options
if ( is_string( $settings_field['callback'] ) && $settings_field['callback'] == 'singular_text_element') {
register_setting( $option_group, $settings_field['args']['option_name'], array( $this->callbacks, 'validate' ) );
}
}
}
// $page, $option_group & $option_name are all the same...
register_setting( $option_group, $option_name, array( $this->callbacks, 'validate' ) );
add_filter( 'option_page_capability_'.$page, array( $this, 'user_settings_capability' ) );
}
public function get_common_document_settings() {
$common_settings = array(
'paper_size' => isset( $this->general_settings['paper_size'] ) ? $this->general_settings['paper_size'] : '',
'font_subsetting' => isset( $this->general_settings['font_subsetting'] ) || ( defined("DOMPDF_ENABLE_FONTSUBSETTING") && DOMPDF_ENABLE_FONTSUBSETTING === true ) ? true : false,
'header_logo' => isset( $this->general_settings['header_logo'] ) ? $this->general_settings['header_logo'] : '',
'header_logo_height' => isset( $this->general_settings['header_logo_height'] ) ? $this->general_settings['header_logo_height'] : '',
'shop_name' => isset( $this->general_settings['shop_name'] ) ? $this->general_settings['shop_name'] : '',
'shop_address' => isset( $this->general_settings['shop_address'] ) ? $this->general_settings['shop_address'] : '',
'footer' => isset( $this->general_settings['footer'] ) ? $this->general_settings['footer'] : '',
'extra_1' => isset( $this->general_settings['extra_1'] ) ? $this->general_settings['extra_1'] : '',
'extra_2' => isset( $this->general_settings['extra_2'] ) ? $this->general_settings['extra_2'] : '',
'extra_3' => isset( $this->general_settings['extra_3'] ) ? $this->general_settings['extra_3'] : '',
);
return $common_settings;
}
public function get_document_settings( $document_type, $output_format = 'pdf' ) {
if ( ! empty( $document_type ) ) {
$option_name = ( 'pdf' === $output_format ) ? "wpo_wcpdf_documents_settings_{$document_type}" : "wpo_wcpdf_documents_settings_{$document_type}_{$output_format}";
return get_option( $option_name, array() );
} else {
return false;
}
}
public function get_output_format( $document = null ) {
$output_format = 'pdf'; // default
if ( isset( $this->debug_settings['html_output'] ) || ( isset( $_REQUEST['output'] ) && 'html' === $_REQUEST['output'] ) ) {
$output_format = 'html';
} elseif ( isset( $_REQUEST['output'] ) && ! empty( $_REQUEST['output'] ) && ! empty( $document ) && in_array( $_REQUEST['output'], $document->output_formats ) ) {
$document_settings = $this->get_document_settings( $document->get_type(), esc_attr( $_REQUEST['output'] ) );
if ( isset( $document_settings['enabled'] ) ) {
$output_format = esc_attr( $_REQUEST['output'] );
}
}
return apply_filters( 'wpo_wcpdf_output_format', $output_format, $document );
}
public function get_output_mode() {
if ( isset( $this->general_settings['download_display'] ) ) {
switch ( $this->general_settings['download_display'] ) {
case 'display':
$output_mode = 'inline';
break;
case 'download':
default:
$output_mode = 'download';
break;
}
} else {
$output_mode = 'download';
}
return $output_mode;
}
public function get_template_path() {
// return default path if no template selected
if ( empty( $this->general_settings['template_path'] ) ) {
return wp_normalize_path( WPO_WCPDF()->plugin_path() . '/templates/Simple' );
}
$installed_templates = $this->get_installed_templates();
$selected_template = $this->general_settings['template_path'];
if ( in_array( $selected_template, $installed_templates ) ) {
return array_search( $selected_template, $installed_templates );
} else {
// unknown template or full template path (filter override)
$template_path = wp_normalize_path( $selected_template );
// add base path, checking if it's not already there
// alternative setups like Bedrock have WP_CONTENT_DIR & ABSPATH separated
if ( defined( 'WP_CONTENT_DIR' ) && ! empty( WP_CONTENT_DIR ) && false !== strpos( WP_CONTENT_DIR, ABSPATH ) ) {
$base_path = wp_normalize_path( ABSPATH );
} else {
$base_path = wp_normalize_path( WP_CONTENT_DIR );
}
if ( ! empty( $template_path ) && false === strpos( $template_path, $base_path ) ) {
$template_path = wp_normalize_path( $base_path . $template_path );
}
}
return $template_path;
}
public function get_installed_templates( $force_reload = false ) {
// because this method can be called (too) early we load from a cached list in those cases
// this cache is updated each time the template settings are saved/updated
if ( ! did_action( 'wpo_wcpdf_init_documents' ) && ( $cached_template_list = $this->get_template_list_cache() ) ) {
return $cached_template_list;
}
// to save resources on the disk operations we only do this once
if ( $force_reload === false && ! empty ( $this->installed_templates ) ) {
return $this->installed_templates;
}
$installed_templates = array();
// get base paths
$template_base_path = ( function_exists( 'WC' ) && is_callable( array( WC(), 'template_path' ) ) ) ? WC()->template_path() : apply_filters( 'woocommerce_template_path', 'woocommerce/' );
$template_base_path = untrailingslashit( $template_base_path );
$template_paths = array (
// note the order: theme before child-theme, so that child theme is always preferred (overwritten)
'default' => WPO_WCPDF()->plugin_path() . '/templates/',
'theme' => get_template_directory() . "/{$template_base_path}/pdf/",
'child-theme' => get_stylesheet_directory() . "/{$template_base_path}/pdf/",
);
$template_paths = apply_filters( 'wpo_wcpdf_template_paths', $template_paths );
foreach ( $template_paths as $template_source => $template_path ) {
$dirs = (array) glob( $template_path . '*' , GLOB_ONLYDIR );
foreach ( $dirs as $dir ) {
$clean_dir = wp_normalize_path( $dir );
$template_name = basename( $clean_dir );
// let child theme override parent theme
$group = ( $template_source == 'child-theme' ) ? 'theme' : $template_source;
$installed_templates[ $clean_dir ] = "{$group}/{$template_name}" ;
}
}
if ( empty( $installed_templates ) ) {
// fallback to Simple template for servers with glob() disabled
$simple_template_path = wp_normalize_path( $template_paths['default'] . 'Simple' );
$installed_templates[$simple_template_path] = 'default/Simple';
}
$installed_templates = apply_filters( 'wpo_wcpdf_installed_templates', $installed_templates );
$this->installed_templates = $installed_templates;
if ( ! empty( $this->template_list_cache ) && array_diff_assoc( $this->template_list_cache, $this->installed_templates ) ) {
$this->set_template_list_cache( $this->installed_templates );
}
return $installed_templates;
}
public function get_template_list_cache() {
$template_list = get_option( 'wpo_wcpdf_installed_template_paths', array() );
if ( ! empty( $template_list ) ) {
$checked_list = array();
$outdated = false;
// cache could be outdated, so we check whether the folders exist
foreach ( $template_list as $path => $template_id ) {
if ( @is_dir( $path ) ) {
$checked_list[$path] = $template_id; // folder exists
continue;
}
$outdated = true;
// folder does not exist, try replacing base if we can locate wp-content
$wp_content_folder = 'wp-content';
if ( ! empty( $path ) && false !== strpos( $path, $wp_content_folder ) && defined( WP_CONTENT_DIR ) ) {
// try wp-content
$relative_path = substr( $path, strrpos( $path, $wp_content_folder ) + strlen( $wp_content_folder ) );
$new_path = WP_CONTENT_DIR . $relative_path;
if ( @is_dir( $new_path ) ) {
$checked_list[$new_path] = $template_id;
}
}
}
if ( $outdated ) {
$this->set_template_list_cache( $checked_list );
}
$this->installed_templates_cache = $checked_list;
return $checked_list;
} else {
return array();
}
}
public function set_template_list_cache( $template_list ) {
$this->template_list_cache = $template_list;
update_option( 'wpo_wcpdf_installed_template_paths', $template_list );
}
public function delete_template_list_cache() {
delete_option( 'wpo_wcpdf_installed_template_paths' );
}
public function general_settings_updated( $old_settings, $settings, $option ) {
if ( is_array( $settings ) && ! empty ( $settings['template_path'] ) ) {
$this->delete_template_list_cache();
$this->set_template_list_cache( $this->get_installed_templates() );
}
}
public function debug_settings_updated( $old_settings, $settings, $option ) {
if ( is_array( $settings ) && is_array( $old_settings ) && empty( $old_settings['pretty_document_links'] ) && ! empty ( $settings['pretty_document_links'] ) ) {
set_transient( 'wpo_wcpdf_flush_rewrite_rules', 'yes', HOUR_IN_SECONDS );
}
}
public function maybe_delete_flush_rewrite_rules_transient() {
if ( get_transient( 'wpo_wcpdf_flush_rewrite_rules' ) ) {
flush_rewrite_rules();
delete_transient( 'wpo_wcpdf_flush_rewrite_rules' );
}
}
public function get_relative_template_path( $absolute_path ) {
if ( defined( 'WP_CONTENT_DIR' ) && ! empty( WP_CONTENT_DIR ) && false !== strpos( WP_CONTENT_DIR, ABSPATH ) ) {
$base_path = wp_normalize_path( ABSPATH );
} else {
$base_path = wp_normalize_path( WP_CONTENT_DIR );
}
return str_replace( $base_path, '', wp_normalize_path( $absolute_path ) );
}
public function maybe_migrate_template_paths( $settings_section = null ) {
// bail if no template is selected yet (fresh install)
if ( empty( $this->general_settings['template_path'] ) ) {
return;
}
$installed_templates = $this->get_installed_templates( true );
$selected_template = wp_normalize_path( $this->general_settings['template_path'] );
$template_match = '';
if ( ! in_array( $selected_template, $installed_templates ) && substr_count( $selected_template, '/' ) > 1 ) {
// search for path match
foreach ( $installed_templates as $path => $template_id ) {
$path = wp_normalize_path( $path );
// check if the last part of the path matches
if ( substr( $path, -strlen( $selected_template ) ) === $selected_template ) {
$template_match = $template_id;
break;
}
}
// fallback to template name if no path match
if ( empty( $template_match ) ) {
$template_ids = array_flip( array_unique( array_combine( $installed_templates, array_map( 'basename', $installed_templates ) ) ) );
$template_name = basename( $selected_template );
if ( ! empty ( $template_ids[$template_name] ) ) {
$template_match = $template_ids[$template_name];
}
}
// migrate setting if we have a match
if ( ! empty( $template_match ) ) {
$this->general_settings['template_path'] = $template_match;
update_option( 'wpo_wcpdf_settings_general', $this->general_settings );
/* translators: 1. path, 2. template ID */
wcpdf_log_error( sprintf( 'Template setting migrated from %1$s to %2$s', $path, $template_id ), 'info' );
}
}
}
public function set_number_store() {
check_ajax_referer( "wpo_wcpdf_next_{$_POST['store']}", 'security' );
// check permissions
if ( ! $this->user_can_manage_settings() ) {
die();
}
$number = ! empty( $_POST['number'] ) ? (int) $_POST['number'] : 0;
if ( $number > 0 ) {
$number_store_method = $this->get_sequential_number_store_method();
$number_store = new Sequential_Number_Store( $_POST['store'], $number_store_method );
$number_store->set_next( $number );
echo wp_kses_post( "next number ({$_POST['store']}) set to {$number}" );
}
die();
}
public function get_sequential_number_store_method() {
global $wpdb;
$method = isset( $this->debug_settings['calculate_document_numbers'] ) ? 'calculate' : 'auto_increment';
// safety first - always use calculate when auto_increment_increment is not 1
$row = $wpdb->get_row("SHOW VARIABLES LIKE 'auto_increment_increment'");
if ( ! empty( $row ) && ! empty( $row->Value ) && $row->Value != 1 ) {
$method = 'calculate';
}
return $method;
}
public function schedule_yearly_reset_numbers() {
if ( ! $this->maybe_schedule_yearly_reset_numbers() ) {
return;
}
// checks AS functions existence
if ( ! function_exists( 'as_schedule_single_action' ) || ! function_exists( 'as_get_scheduled_actions' ) ) {
return;
}
$next_year = strval( intval( current_time( 'Y' ) ) + 1 );
$datetime = new \WC_DateTime( "{$next_year}-01-01 00:00:01", new \DateTimeZone( wc_timezone_string() ) );
$lock = new Semaphore( $this->lock_name, $this->lock_time, array( wc_get_logger() ), $this->lock_context );
$hook = 'wpo_wcpdf_schedule_yearly_reset_numbers';
// checks if there are pending actions
$scheduled_actions = count( as_get_scheduled_actions( array(
'hook' => $hook,
'status' => \ActionScheduler_Store::STATUS_PENDING,
) ) );
// if no concurrent actions sets the action
if ( $scheduled_actions < 1 ) {
if ( $lock->lock( $this->lock_retries ) ) {
try {
$action_id = as_schedule_single_action( $datetime->getTimestamp(), $hook );
if ( ! empty( $action_id ) ) {
wcpdf_log_error(
"Yearly document numbers reset scheduled with the action id: {$action_id}",
'info'
);
} else {
wcpdf_log_error(
'The yearly document numbers reset action schedule failed!',
'critical'
);
}
} catch ( \Exception $e ) {
$lock->log( $e, 'critical' );
} catch ( \Error $e ) {
$lock->log( $e, 'critical' );
}
$lock->release();
} else {
$lock->log( "Couldn't get the lock!", 'critical' );
}
} else {
wcpdf_log_error(
"Number of concurrent yearly document numbers reset actions found: {$scheduled_actions}",
'error'
);
if ( function_exists( 'as_unschedule_all_actions' ) ) {
as_unschedule_all_actions( $hook );
}
// reschedule
$this->schedule_yearly_reset_numbers();
}
}
public function yearly_reset_numbers() {
$lock = new Semaphore( $this->lock_name, $this->lock_time, array( wc_get_logger() ), $this->lock_context );
if ( $lock->lock( $this->lock_retries ) ) {
try {
// reset numbers
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
$number_stores = array();
foreach ( $documents as $document ) {
if ( is_callable( array( $document, 'get_sequential_number_store' ) ) ) {
$number_stores[$document->get_type()] = $document->get_sequential_number_store();
}
}
// log reset number events
if ( ! empty( $number_stores ) ) {
foreach( $number_stores as $document_type => $number_store ) {
if ( $number_store->get_next() === 1 ) {
wcpdf_log_error(
"Yearly number reset succeed for '{$document_type}' with database table name: {$number_store->table_name}",
'info'
);
} else {
wcpdf_log_error(
"An error occurred while trying to reset yearly number for '{$document_type}' with database table name: {$number_store->table_name}",
'error'
);
}
}
}
} catch ( \Exception $e ) {
$lock->log( $e, 'critical' );
} catch ( \Error $e ) {
$lock->log( $e, 'critical' );
}
$lock->release();
} else {
$lock->log( "Couldn't get the lock!", 'critical' );
}
// reschedule the action for the next year
$this->schedule_yearly_reset_numbers();
}
public function maybe_schedule_yearly_reset_numbers() {
$schedule = false;
foreach ( WPO_WCPDF()->documents->get_documents( 'all' ) as $document ) {
if ( isset( $document->settings['reset_number_yearly'] ) ) {
$schedule = true;
break;
}
}
// unschedule existing actions
if ( ! $schedule && function_exists( 'as_unschedule_all_actions' ) ) {
as_unschedule_all_actions( 'wpo_wcpdf_schedule_yearly_reset_numbers' );
}
return $schedule;
}
public function yearly_reset_action_is_scheduled() {
$is_scheduled = false;
$scheduled_actions = as_get_scheduled_actions( array(
'hook' => 'wpo_wcpdf_schedule_yearly_reset_numbers',
'status' => \ActionScheduler_Store::STATUS_PENDING,
) );
if ( ! empty( $scheduled_actions ) ) {
$total_actions = count( $scheduled_actions );
if ( $total_actions === 1 ) {
$is_scheduled = true;
} else {
$message = sprintf(
/* translators: total scheduled actions */
__( 'Only 1 scheduled action should exist for the yearly reset of the numbering system, but %s were found', 'woocommerce-pdf-invoices-packing-slips' ),
$total_actions
);
wcpdf_log_error( $message );
}
}
return $is_scheduled;
}
public function get_media_upload_setting_html() {
check_ajax_referer( 'wpo_wcpdf_get_media_upload_setting_html', 'security' );
// check permissions
if ( ! $this->user_can_manage_settings() ) {
wp_send_json_error();
}
// get previous (default) args and preset current
$args = $_POST['args'];
$args['current'] = absint( $_POST['attachment_id'] );
// get settings HTML
ob_start();
$this->callbacks->media_upload( $args );
$html = ob_get_clean();
return wp_send_json_success( $html );
}
public function move_setting_after_id( $settings, $insert_settings, $after_setting_id ) {
$pos = 1; // this is already +1 to insert after the actual pos
foreach ( $settings as $setting ) {
if ( isset( $setting['id'] ) && $setting['id'] == $after_setting_id ) {
$section = $setting['section'];
break;
} else {
$pos++;
}
}
// replace section
if ( isset( $section ) ) {
foreach ( $insert_settings as $key => $insert_setting ) {
$insert_settings[$key]['section'] = $section;
}
} else {
$empty_section = array(
array(
'type' => 'section',
'id' => 'custom',
'title' => '',
'callback' => 'section',
),
);
$insert_settings = array_merge( $empty_section, $insert_settings );
}
// insert our api settings
$new_settings = array_merge( array_slice( $settings, 0, $pos, true ), $insert_settings, array_slice( $settings, $pos, NULL, true ) );
return $new_settings;
}
}
endif; // class_exists

View File

@@ -0,0 +1,281 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Setup_Wizard' ) ) :
class Setup_Wizard {
/** @var string Currenct Step */
private $step = '';
/** @var array Steps for the setup wizard */
private $steps = array();
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
if ( WPO_WCPDF()->settings->user_can_manage_settings() ) {
add_action( 'admin_menu', array( $this, 'admin_menus' ) );
add_action( 'admin_init', array( $this, 'setup_wizard' ) );
}
}
/**
* Add admin menus/screens.
*/
public function admin_menus() {
add_dashboard_page( '', '', 'manage_options', 'wpo-wcpdf-setup', '' );
}
/**
* Show the setup wizard.
*/
public function setup_wizard() {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
if ( empty( $_GET['page'] ) || 'wpo-wcpdf-setup' !== $_GET['page'] ) {
return;
}
if ( is_null ( get_current_screen() ) ) {
set_current_screen();
}
$this->steps = array(
'shop-name' => array(
'name' => __( 'Shop Name', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/shop-name.php',
),
'logo' => array(
'name' => __( 'Your logo', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/logo.php',
),
'attach-to' => array(
'name' => __( 'Attachments', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/attach-to.php',
),
'display-options' => array(
'name' => __( 'Display options', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/display-options.php',
),
'paper-format' => array(
'name' => __( 'Paper format', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/paper-format.php',
),
'show-action-buttons' => array(
'name' => __( 'Action buttons', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/show-action-buttons.php',
),
'good-to-go' => array(
'name' => __( 'Ready!', 'woocommerce-pdf-invoices-packing-slips' ),
'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/good-to-go.php',
),
);
$this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : current( array_keys( $this->steps ) );
wp_enqueue_style(
'wpo-wcpdf-setup',
WPO_WCPDF()->plugin_url() . '/assets/css/setup-wizard'.$suffix.'.css',
array( 'dashicons', 'install' ),
WPO_WCPDF_VERSION
);
wp_register_script(
'wpo-wcpdf-media-upload',
WPO_WCPDF()->plugin_url() . '/assets/js/media-upload'.$suffix.'.js',
array( 'jquery', 'media-editor', 'mce-view' ),
WPO_WCPDF_VERSION
);
wp_register_script(
'wpo-wcpdf-setup',
WPO_WCPDF()->plugin_url() . '/assets/js/setup-wizard'.$suffix.'.js',
array( 'jquery', 'wpo-wcpdf-media-upload' ),
WPO_WCPDF_VERSION
);
wp_enqueue_media();
$step_keys = array_keys( $this->steps );
if ( end( $step_keys ) === $this->step ) {
wp_register_script(
'wpo-wcpdf-setup-confetti',
WPO_WCPDF()->plugin_url() . '/assets/js/confetti'.$suffix.'.js',
array( 'jquery' ),
WPO_WCPDF_VERSION
);
}
if ( ! empty( $_POST['save_step'] ) ) {
$this->save_step();
}
// disable query monitor during wizard
add_filter( 'qm/dispatch/html', '__return_false' );
ob_start();
$this->setup_wizard_header();
$this->setup_wizard_steps();
$this->setup_wizard_content();
$this->setup_wizard_footer();
exit;
}
/**
* Setup Wizard Header.
*/
public function setup_wizard_header() {
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?> class="wpo-wizard">
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php esc_html_e( 'PDF Invoices & Packing Slips for WooCommerce &rsaquo; Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></title>
<?php wp_print_scripts( 'wpo-wcpdf-setup' ); ?>
<?php wp_print_scripts( 'wpo-wcpdf-setup-confetti' ); ?>
<?php do_action( 'admin_print_styles' ); ?>
<?php do_action( 'admin_head' ); ?>
</head>
<body class="wpo-wcpdf-setup wp-core-ui">
<?php if( $this->step == 'good-to-go' ) { echo "<div id='confetti'></div>"; } ?>
<form method="post">
<?php
}
/**
* Output the steps.
*/
public function setup_wizard_steps() {
$output_steps = $this->steps;
// array_shift( $output_steps );
?>
<div class="wpo-setup-card">
<h1 class="wpo-plugin-title"><?php esc_html_e( 'PDF Invoices & Packing Slips', 'woocommerce-pdf-invoices-packing-slips' ); ?></h1>
<ol class="wpo-progress-bar">
<?php foreach ( $output_steps as $step_key => $step ) : ?>
<li class="<?php
if ( $step_key === $this->step ) {
echo 'active';
} elseif ( array_search( $this->step, array_keys( $this->steps ) ) > array_search( $step_key, array_keys( $this->steps ) ) ) {
echo 'completed';
}
?>"><a href="<?php echo esc_attr( $this->get_step_link( $step_key ) ); ?>" ><div class="wpo-progress-marker"></div></a></li>
<?php endforeach; ?>
</ol>
<?php
}
/**
* Output the content for the current step.
*/
public function setup_wizard_content() {
echo '<div class="wpo-setup-content">';
include( $this->steps[ $this->step ]['view'] );
echo '</div>';
}
/**
* Setup Wizard Footer.
*/
public function setup_wizard_footer() {
?>
<input type="hidden" name="wpo_wcpdf_step" value="<?php echo esc_attr( $this->step ); ?>">
<div class="wpo-setup-buttons">
<?php if ( $step = $this->get_step( -1 ) ): ?>
<a href="<?php echo esc_attr( $this->get_step_link( $step ) ); ?>" class="wpo-button-previous"><?php esc_html_e( 'Previous', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
<?php endif ?>
<!-- <input type="submit" class="wpo-button-next" value="Next" /> -->
<?php if ( $step = $this->get_step( 1 ) ): ?>
<?php wp_nonce_field( 'wpo-wcpdf-setup' ); ?>
<input type="submit" class="wpo-button-next" value="<?php esc_attr_e( 'Next', 'woocommerce-pdf-invoices-packing-slips' ); ?>" name="save_step" />
<a href="<?php echo esc_attr( $this->get_step_link( $step ) ); ?>" class="wpo-skip-step"><?php esc_html_e( 'Skip this step', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
<?php else: ?>
<a href="<?php echo esc_attr( $this->get_step_link($step) ); ?>" class="wpo-button-next"><?php esc_html_e( 'Finish', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
<?php endif ?>
</div>
</div>
</form>
<?php do_action( 'admin_footer' ); // for media uploader templates ?>
</body>
</html>
<?php
}
public function get_step_link( $step ) {
$step_keys = array_keys( $this->steps );
if ( end( $step_keys ) === $this->step && empty( $step ) ) {
return admin_url('admin.php?page=wpo_wcpdf_options_page');
}
return esc_url_raw( add_query_arg( 'step', $step ) );
}
public function get_step( $delta ) {
$step_keys = array_keys( $this->steps );
$current_step_pos = array_search( $this->step, $step_keys );
$new_step_pos = $current_step_pos + $delta;
if ( isset( $step_keys[$new_step_pos] ) ) {
return $step_keys[$new_step_pos];
} else {
return false;
}
}
public function save_step() {
if ( isset( $this->steps[ $this->step ]['handler'] ) ) {
check_admin_referer( 'wpo-wcpdf-setup' );
// for doing more than just saving an option value
call_user_func( $this->steps[ $this->step ]['handler'] );
} else {
$user_id = get_current_user_id();
$hidden = get_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', true );
if ( ! empty( $_POST['wcpdf_settings'] ) && is_array( $_POST['wcpdf_settings'] ) ) {
check_admin_referer( 'wpo-wcpdf-setup' );
foreach ( $_POST['wcpdf_settings'] as $option => $settings ) {
// sanitize posted settings
foreach ( $settings as $key => $value ) {
if ( $key == 'shop_address' && function_exists( 'sanitize_textarea_field' ) ) {
$sanitize_function = 'sanitize_textarea_field';
} else {
$sanitize_function = 'sanitize_text_field';
}
$value = stripslashes_deep( $value );
if ( is_array( $value ) ) {
$settings[$key] = array_map( $sanitize_function, $value );
} else {
$settings[$key] = call_user_func( $sanitize_function, $value );
}
}
$current_settings = get_option( $option, array() );
$new_settings = $settings + $current_settings;
update_option( $option, $new_settings );
}
} elseif ( $_POST['wpo_wcpdf_step'] == 'show-action-buttons' ) {
if ( ! empty( $_POST['wc_show_action_buttons'] ) ) {
$hidden = array_filter( $hidden, function( $setting ){ return $setting !== 'wc_actions'; } );
update_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', $hidden );
} else {
array_push( $hidden, 'wc_actions' );
update_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', $hidden );
}
}
}
wp_redirect( esc_url_raw( $this->get_step_link( $this->get_step(1) ) ) );
}
}
endif; // class_exists

View File

@@ -0,0 +1,239 @@
<?php
namespace WPO\WC\PDF_Invoices;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Updraft_Semaphore_3_0' ) ) :
/**
* Class Updraft_Semaphore_3_0
*
* This class is much simpler to use than the the previous series, as it has dropped support for complicated cases that were not being used. It also now only uses a single row in the options database, and takes care of creating it itself internally.
*
* Logging, though, may be noisier, unless your loggers are taking note of the log level and only registering what is required.
*
* Example of use (a lock that will expire if not released within 300 seconds)
*
* See test.php for a longer example (including logging).
*
* $my_lock = new Updraft_Semaphore_3_0('my_lock_name', 300);
* // If getting the lock does not succeed first time, try again up to twice
* if ($my_lock->lock(2)) {
* try {
* // do stuff ...
* } catch (Exception $e) {
* // We are making sure we release the lock in case of an error
* } catch (Error $e) {
* // We are making sure we release the lock in case of an error
* }
* $my_lock->release();
* } else {
* error_log("Sorry, could not get the lock");
* }
*/
class Updraft_Semaphore_3_0 {
// Time after which the lock will expire (in seconds)
protected $locked_for;
// Name for the lock in the WP options table
protected $option_name;
// Lock status - a boolean
protected $acquired = false;
// An array of loggers
protected $loggers = array();
// Context for loggers
protected $context = array();
/**
* Constructor. Instantiating does not lock anything, but sets up the details for future operations.
*
* @param String $name - a unique (across the WP site) name for the lock. Should be no more than 51 characters in length (because of the use of the WP options table, with some further characters used internally)
* @param Integer $locked_for - time (in seconds) after which the lock will expire if not released. This needs to be positive if you don't want bad things to happen.
* @param Array $loggers - an array of loggers
*/
public function __construct( $name, $locked_for = 300, $loggers = array(), $context = array() ) {
$this->option_name = 'updraft_lock_'.$name;
$this->locked_for = $locked_for;
$this->loggers = $loggers;
$this->context = $context;
}
/**
* Internal function to make sure that the lock is set up in the database
*
* @return Integer - 0 means 'failed' (which could include that someone else concurrently created it); 1 means 'already existed'; 2 means 'exists, because we created it). The intention is that non-zero results mean that the lock exists.
*/
private function ensure_database_initialised() {
global $wpdb;
$sql = $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name = %s", $this->option_name );
if ( 1 === (int) $wpdb->get_var( $sql ) ) {
$this->log( 'Lock option ('.$this->option_name.', '.$wpdb->options.') already existed in the database', 'debug ');
return 1;
}
$sql = $wpdb->prepare( "INSERT INTO {$wpdb->options} (option_name, option_value, autoload) VALUES(%s, '0', 'no');", $this->option_name );
$rows_affected = $wpdb->query( $sql );
if ( $rows_affected > 0 ) {
$this->log( 'Lock option ('.$this->option_name.', '.$wpdb->options.') was created in the database', 'debug' );
} else {
$this->log( 'Lock option ('.$this->option_name.', '.$wpdb->options.') failed to be created in the database (could already exist)', 'notice' );
}
return ( $rows_affected > 0 ) ? 2 : 0;
}
/**
* Attempt to acquire the lock. If it was already acquired, then nothing extra will be done (the method will be a no-op).
*
* @param Integer $retries - how many times to retry (after a 1 second sleep each time)
*
* @return Boolean - whether the lock was successfully acquired or not
*/
public function lock($retries = 0) {
if ( $this->acquired ) {
return true;
}
global $wpdb;
$time_now = time();
$acquire_until = $time_now + $this->locked_for;
$sql = $wpdb->prepare( "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value < %d", $acquire_until, $this->option_name, $time_now );
if ( 1 === $wpdb->query( $sql ) ) {
$this->log( 'Lock ('.$this->option_name.', '.$wpdb->options.') acquired', 'info' );
$this->acquired = true;
return true;
}
// See if the failure was caused by the row not existing (we check this only after failure, because it should only occur once on the site)
if ( ! $this->ensure_database_initialised() ) {
return false;
}
do {
// Now that the row has been created, try again
if ( 1 === $wpdb->query( $sql ) ) {
$this->log( 'Lock ('.$this->option_name.', '.$wpdb->options.') acquired after initialising the database', 'info' );
$this->acquired = true;
return true;
}
$retries--;
if ( $retries >=0 ) {
$this->log( 'Lock ('.$this->option_name.', '.$wpdb->options.') not yet acquired; sleeping', 'debug' );
sleep( 1 );
// As a second has passed, update the time we are aiming for
$time_now = time();
$acquire_until = $time_now + $this->locked_for;
$sql = $wpdb->prepare( "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value < %d", $acquire_until, $this->option_name, $time_now );
}
} while ( $retries >= 0 );
$this->log( 'Lock ('.$this->option_name.', '.$wpdb->options.') could not be acquired (it is locked)', 'info' );
return false;
}
/**
* Release the lock
*
* N.B. We don't attempt to unlock it unless we locked it. i.e. Lost locks are left to expire rather than being forced. (If we want to force them, we'll need to introduce a new parameter).
*
* @return Boolean - if it returns false, then the lock was apparently not locked by us (and the caller will most likely therefore ignore the result, whatever it is).
*/
public function release() {
if ( ! $this->acquired ) {
return false;
}
global $wpdb;
$sql = $wpdb->prepare( "UPDATE {$wpdb->options} SET option_value = '0' WHERE option_name = %s", $this->option_name );
$this->log( 'Lock option ('.$this->option_name.', '.$wpdb->options.') released', 'info' );
$result = (int) $wpdb->query($sql) === 1;
$this->acquired = false;
return $result;
}
/**
* Cleans up the DB of any residual data. This should not be used as part of ordinary unlocking; only as part of deinstalling, or if you otherwise know that the lock will not be used again. If calling this, it's redundant to first unlock (and a no-op to attempt to do so afterwards).
*/
public function delete() {
$this->acquired = false;
global $wpdb;
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name = %s", $this->option_name ) );
$this->log( 'Lock option ('.$this->option_name.', '.$wpdb->options.') was deleted from the database' );
}
/**
* Captures and logs any given messages
*
* @param String $message - the error message
* @param String $level - the message level (debug, notice, info, warning, error)
* @param Array $context - Optional. Additional information for log handlers.
*/
public function log( $message, $level = 'info', $context = array() ) {
$context = ! empty( $context ) ? $context : $this->context;
if ( isset( $this->loggers ) ) {
foreach ( $this->loggers as $logger ) {
if ( ! empty( $context ) ) {
$logger->log( $level, $message, $context );
} else {
$logger->log( $level, $message );
}
}
}
}
/**
* Sets the list of loggers for this instance (removing any others).
*
* @param Array $loggers - the loggers for this task
*/
public function set_loggers( $loggers ) {
$this->loggers = array();
foreach ( $loggers as $logger ) {
$this->add_logger( $logger );
}
}
/**
* Add a logger to loggers list
*
* @param Callable $logger - a logger (a method with a callable function 'log', taking string parameters $level $message)
*/
public function add_logger( $logger ) {
$this->loggers[] = $logger;
}
/**
* Return the current list of loggers
*
* @return Array
*/
public function get_loggers() {
return $this->loggers;
}
}
endif; // class_exists

View File

@@ -0,0 +1,317 @@
<?php
namespace WPO\WC\PDF_Invoices\Compatibility;
defined( 'ABSPATH' ) or exit;
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Compatibility\\Third_Party_Plugins' ) ) :
/**
* Third party plugin compatibility class.
*
* @since 2.0
*/
class Third_Party_Plugins {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
// WooCommerce Subscriptions compatibility
if ( class_exists( 'WC_Subscriptions' ) ) {
if ( version_compare( \WC_Subscriptions::$version, '2.0', '<' ) ) {
add_action( 'woocommerce_subscriptions_renewal_order_created', array( $this, 'woocommerce_subscriptions_renewal_order_created' ), 10, 4 );
} elseif ( version_compare( \WC_Subscriptions::$version, '2.5', '<' ) ) {
add_filter( 'wcs_renewal_order_meta', array( $this, 'wcs_renewal_order_meta' ), 10, 3 );
add_filter( 'wcs_resubscribe_order_meta', array( $this, 'wcs_renewal_order_meta' ), 10, 3 );
} else {
add_filter( 'wc_subscription_renewal_order_data', array( $this, 'wcs_renewal_order_meta' ), 10, 3 );
add_filter( 'wc_subscriptions_resubscribe_order_data', array( $this, 'wcs_renewal_order_meta' ), 10, 3 );
}
}
// WooCommerce Product Bundles compatibility (add row classes)
add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
// WPC Bundles compatibility (add row classes)
add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_wpc_product_bundles_classes' ), 10, 4 );
// WooCommerce Chained Products compatibility (add row classes)
add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
// WooCommerce Composite Products compatibility (add row classes)
add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_composite_product_class' ), 10, 4 );
// WooCommerce Order Status & Actions Manager emails compatibility
if (class_exists('WC_Custom_Status')) {
add_filter( 'wpo_wcpdf_wc_emails', array( $this, 'wc_order_status_actions_emails' ), 10, 1 );
}
// Aelia Currency Switcher compatibility
$currency_switcher_active = !empty($GLOBALS['woocommerce-aelia-currencyswitcher']);
if ( $currency_switcher_active ) {
add_action( 'wpo_wcpdf_before_html', array( $this, 'aelia_currency_formatting' ), 10, 2 );
}
// Avoid double images from WooCommerce German Market
if ( class_exists('WGM_Product') ) {
add_action( 'wpo_wcpdf_before_html', array( $this, 'remove_wgm_thumbnails' ), 10, 2 );
add_action( 'wpo_wcpdf_after_html', array( $this, 'restore_wgm_thumbnails' ), 10, 2 );
}
}
/**
* Reset invoice data for WooCommerce subscription renewal orders
* https://wordpress.org/support/topic/subscription-renewal-duplicate-invoice-number?replies=6#post-6138110
*/
public function woocommerce_subscriptions_renewal_order_created ( $renewal_order, $original_order, $product_id, $new_order_role ) {
$this->reset_invoice_data( $renewal_order );
return $renewal_order;
}
public function reset_invoice_data ( $order ) {
if ( ! is_object( $order ) ) {
$order = wc_get_order( $order );
}
// delete invoice number, invoice date & invoice exists meta
$order->delete_meta_data( '_wcpdf_invoice_number' );
$order->delete_meta_data( '_wcpdf_invoice_number_data' );
$order->delete_meta_data( '_wcpdf_formatted_invoice_number' );
$order->delete_meta_data( '_wcpdf_invoice_date' );
$order->delete_meta_data( '_wcpdf_invoice_exists' );
$order->save_meta_data();
}
/**
* Removes documents meta from WooCommerce Subscriptions renewal order
*/
public function wcs_renewal_order_meta ( $meta, $to_order, $from_order ) {
if ( ! empty( $meta ) ) {
$documents = WPO_WCPDF()->documents->get_documents();
$documents_meta = array();
foreach ( $documents as $document ) {
$document_data_keys = apply_filters( 'wpo_wcpdf_delete_document_data_keys', array(
'settings',
'date',
'date_formatted',
'number',
'number_data',
'notes',
'exists',
), $document );
$document_meta = array_map( function ( $data_key ) use ( $document ) {
return "_wcpdf_{$document->slug}_{$data_key}";
}, $document_data_keys );
$document_meta[] = "_wcpdf_formatted_{$document->slug}_number"; // legacy meta key
$documents_meta = array_merge( $documents_meta, $document_meta );
}
foreach ( $meta as $key => $value ) {
if ( in_array( $value['meta_key'], $documents_meta ) ) {
unset( $meta[$key] );
}
}
}
return $meta;
}
/**
* WooCommerce Product Bundles
* @param string $classes CSS classes for item row (tr)
* @param string $document_type PDF Document type
* @param object $order WC_Order order
* @param int $item_id WooCommerce Item ID
*/
public function add_product_bundles_classes ( $classes, $document_type, $order, $item_id = 0 ) {
if ( !class_exists('WC_Bundles') ) {
return $classes;
}
$item_id = ! empty( $item_id ) ? $item_id : $this->get_item_id_from_classes( $classes );
if ( empty( $item_id ) ) {
return $classes;
}
if ( $bundled_by = wc_get_order_item_meta( $item_id, '_bundled_by', true ) ) {
$classes = $classes . ' bundled-item';
// check bundled item visibility
if ( $hidden = wc_get_order_item_meta( $item_id, '_bundled_item_hidden', true ) ) {
$classes = $classes . ' hidden';
}
return $classes;
} elseif ( $bundled_items = wc_get_order_item_meta( $item_id, '_bundled_items', true ) ) {
return $classes . ' product-bundle';
}
return $classes;
}
/**
* WPC Product Bundles
* @param string $classes CSS classes for item row (tr)
* @param string $document_type PDF Document type
* @param object $order WC_Order order
* @param int $item_id WooCommerce Item ID
*/
public function add_wpc_product_bundles_classes ( $classes, $document_type, $order, $item_id = 0 ) {
if ( ! class_exists( 'WPCleverWoosb' ) ) {
return $classes;
}
$item_id = ! empty( $item_id ) ? $item_id : $this->get_item_id_from_classes( $classes );
if ( empty( $item_id ) ) {
return $classes;
}
// Add row classes
$refunded_item_id = wc_get_order_item_meta( $item_id, '_refunded_item_id', true );
$class_item_id = ! empty( $refunded_item_id ) ? $refunded_item_id : $item_id;
if ( $bundled_by = wc_get_order_item_meta( $class_item_id, '_woosb_parent_id', true ) ) {
$classes = $classes . ' bundled-item';
} elseif ( $bundled_items = wc_get_order_item_meta( $class_item_id, '_woosb_ids', true ) ) {
$classes = $classes . ' product-bundle';
}
return $classes;
}
/**
* WooCommerce Chained Products
* @param string $classes CSS classes for item row (tr)
* @param string $document_type PDF Document type
* @param object $order WC_Order order
* @param int $item_id WooCommerce Item ID
*/
public function add_chained_product_class ( $classes, $document_type, $order, $item_id = 0 ) {
if ( !class_exists('SA_WC_Chained_Products') && !class_exists('WC_Chained_Products') ) {
return $classes;
}
$item_id = !empty($item_id) ? $item_id : $this->get_item_id_from_classes( $classes );
if ( empty($item_id) ) {
return $classes;
}
if ( $chained_product_of = wc_get_order_item_meta( $item_id, '_chained_product_of', true ) ) {
return $classes . ' chained-product';
}
return $classes;
}
/**
* WooCommerce Composite Products
* @param string $classes CSS classes for item row (tr)
* @param string $document_type PDF Document type
* @param object $order WC_Order order
* @param int $item_id WooCommerce Item ID
*/
public function add_composite_product_class ( $classes, $document_type, $order, $item_id = 0 ) {
if ( !function_exists('wc_cp_is_composited_order_item') || !function_exists('wc_cp_is_composite_container_order_item') ) {
return $classes;
}
$item_id = !empty($item_id) ? $item_id : $this->get_item_id_from_classes( $classes );
if ( empty($item_id) ) {
return $classes;
}
// get order item object
$order_items = $order->get_items();
foreach ($order_items as $order_item_id => $order_item) {
if ($order_item_id == $item_id) {
if ( wc_cp_is_composited_order_item( $order_item, $order ) ) {
$classes .= ' component_table_item';
} elseif ( wc_cp_is_composite_container_order_item( $order_item ) ) {
$classes .= ' component_container_table_item';
}
break;
}
}
return $classes;
}
/**
* Backwards compatibility helper function: try to get item ID from row class
* @param string $classes CSS classes for item row (tr)
*/
public function get_item_id_from_classes ( $classes ) {
$class_array = explode(' ', $classes);
foreach ($class_array as $class) {
if (is_numeric($class)) {
$item_id = $class;
break;
}
}
// if still empty, we lost the item id somewhere :(
if (empty($item_id)) {
return false;
} else {
return $item_id;
}
}
/**
* WooCommerce Order Status & Actions Manager emails compatibility
*/
public function wc_order_status_actions_emails ( $emails ) {
// get list of custom statuses from WooCommerce Custom Order Status & Actions
// status slug => status name
$custom_statuses = \WC_Custom_Status::get_status_list_names();
// append _email to slug (=email_id) and add to emails list
foreach ($custom_statuses as $status_slug => $status_name) {
$emails[$status_slug.'_email'] = $status_name;
}
return $emails;
}
/**
* Aelia Currency Switcher compatibility
* Applies decimal & Thousand separator settings
*/
function aelia_currency_formatting( $document_type, $document ) {
add_filter( 'wc_price_args', array( $this, 'aelia_currency_price_args' ), 10, 1 );
}
function aelia_currency_price_args( $args ) {
if ( !empty( $args['currency'] ) && class_exists("\\Aelia\\WC\\CurrencySwitcher\\WC_Aelia_CurrencySwitcher") ) {
$cs_settings = \Aelia\WC\CurrencySwitcher\WC_Aelia_CurrencySwitcher::settings();
$args['decimal_separator'] = $cs_settings->get_currency_decimal_separator( $args['currency'] );
$args['thousand_separator'] = $cs_settings->get_currency_thousand_separator( $args['currency'] );
}
return $args;
}
/**
* Avoid double images from German Market: remove filter
*/
function remove_wgm_thumbnails( $document_type, $document ) {
remove_filter( 'woocommerce_order_item_name', array( 'WGM_Product', 'add_thumbnail_to_order' ), 100, 3 );
}
/**
* Restore above
*/
function restore_wgm_thumbnails( $document_type, $document ) {
if ( is_callable( array( 'WGM_Product', 'add_thumbnail_to_order' ) ) && get_option( 'german_market_product_images_in_order', 'off' ) == 'on' ) {
add_filter( 'woocommerce_order_item_name', array( 'WGM_Product', 'add_thumbnail_to_order' ), 100, 3 );
}
}
}
endif; // Class exists check

View File

@@ -0,0 +1,61 @@
<?php
/**
* WooCommerce OrderUtil compatibility class.
*
* @since 3.5
*/
namespace WPO\WC\PDF_Invoices\Compatibility;
defined( 'ABSPATH' ) or exit;
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Compatibility\\Order_Util' ) ) :
class Order_Util {
public $wc_order_util_class_object;
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
$this->wc_order_util_class_object = $this->get_wc_order_util_class();
}
public function get_wc_order_util_class() {
if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) ) {
return \Automattic\WooCommerce\Utilities\OrderUtil::class;
} else {
return false;
}
}
public function get_order_type( $order_id ) {
if ( $this->wc_order_util_class_object && is_callable( [ $this->wc_order_util_class_object, 'get_order_type' ] ) ) {
return $this->wc_order_util_class_object::get_order_type( intval( $order_id ) );
} else {
return get_post_type( intval( $order_id ) );
}
}
public function custom_orders_table_usage_is_enabled() {
if ( $this->wc_order_util_class_object && is_callable( [ $this->wc_order_util_class_object, 'custom_orders_table_usage_is_enabled' ] ) ) {
return $this->wc_order_util_class_object::custom_orders_table_usage_is_enabled();
} else {
return false;
}
}
public function is_wc_admin_page() {
return class_exists( 'Automattic\WooCommerce\Admin\PageController' ) &&
is_callable( array( '\\Automattic\\WooCommerce\\Admin\\PageController', 'is_admin_or_embed_page' ) ) &&
\Automattic\WooCommerce\Admin\PageController::is_admin_or_embed_page();
}
}
endif; // Class exists check

View File

@@ -0,0 +1,185 @@
<?php
namespace WPO\WC\PDF_Invoices\Documents;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Bulk_Document' ) ) :
/**
* Bulk Document
*
* Wraps single documents in a bulk document
*/
class Bulk_Document {
/**
* Document type.
* @var String
*/
public $type;
/**
* Wrapper document - used for filename etc.
* @var String
*/
public $wrapper_document;
/**
* Order IDs.
* @var array
*/
public $order_ids;
public $is_bulk;
public $output_formats;
public function __construct( $document_type, $order_ids = array() ) {
$this->type = $document_type;
$this->order_ids = $order_ids;
$this->is_bulk = true;
// output formats (placed after parent construct to override the abstract default)
$this->output_formats = apply_filters( "wpo_wcpdf_{$this->type}_output_formats", array( 'pdf' ), $this );
}
public function exists() {
$exists = false;
foreach ( $this->order_ids as $order_id ) {
$document = wcpdf_get_document( $this->type, $order_id );
if ( $document && is_callable( array( $document, 'exists' ) ) && $document->exists() ) {
$exists = true;
break;
}
}
return $exists;
}
public function is_enabled( $output_format = 'pdf' ) {
if ( in_array( $output_format, $this->output_formats ) ) {
return true;
}
return false;
}
public function get_type() {
return $this->type;
}
public function get_pdf() {
do_action( 'wpo_wcpdf_before_pdf', $this->get_type(), $this );
// temporarily apply filters that need to be removed again after the pdf is generated
$pdf_filters = apply_filters( 'wpo_wcpdf_pdf_filters', array(), $this );
$this->add_filters( $pdf_filters );
$html = $this->get_html();
$pdf_settings = array(
'paper_size' => apply_filters( 'wpo_wcpdf_paper_format', $this->wrapper_document->get_setting( 'paper_size', 'A4' ), $this->get_type(), $this ),
'paper_orientation' => apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $this->get_type(), $this ),
'font_subsetting' => $this->wrapper_document->get_setting( 'font_subsetting', false ),
);
$pdf_maker = wcpdf_get_pdf_maker( $html, $pdf_settings, $this );
$pdf = apply_filters( 'wpo_wcpdf_pdf_data', $pdf_maker->output(), $this );
do_action( 'wpo_wcpdf_after_pdf', $this->get_type(), $this );
// remove temporary filters
$this->remove_filters( $pdf_filters );
return $pdf;
}
public function get_html() {
// temporarily apply filters that need to be removed again after the html is generated
$html_filters = apply_filters( 'wpo_wcpdf_html_filters', array(), $this );
$this->add_filters( $html_filters );
do_action( 'wpo_wcpdf_before_html', $this->get_type(), $this );
$html_content = array();
foreach ( $this->order_ids as $key => $order_id ) {
do_action( 'wpo_wcpdf_process_template_order', $this->get_type(), $order_id );
$order = wc_get_order( $order_id );
if ( $document = wcpdf_get_document( $this->get_type(), $order, true ) ) {
$html_content[ $key ] = $document->get_html( array( 'wrap_html_content' => false ) );
}
}
// get wrapper document & insert body content
$this->wrapper_document = wcpdf_get_document( $this->get_type(), null );
$html = $this->wrapper_document->wrap_html_content( $this->merge_documents( $html_content ) );
do_action( 'wpo_wcpdf_after_html', $this->get_type(), $this );
// remove temporary filters
$this->remove_filters( $html_filters );
return $html;
}
public function merge_documents( $html_content ) {
// insert page breaks merge
$page_break = "\n<div style=\"page-break-before: always;\"></div>\n";
$html = implode( $page_break, $html_content );
return apply_filters( 'wpo_wcpdf_merged_bulk_document_content', $html, $html_content, $this );
}
public function output_pdf( $output_mode = 'download' ) {
$pdf = $this->get_pdf();
wcpdf_pdf_headers( $this->get_filename(), $output_mode, $pdf );
echo $pdf;
die();
}
public function output_html() {
echo $this->get_html();
die();
}
public function get_filename( $context = 'download', $args = array() ) {
if ( empty( $this->wrapper_document ) ) {
$this->wrapper_document = wcpdf_get_document( $this->get_type(), null );
}
$default_args = array(
'order_ids' => $this->order_ids,
);
$args = $args + $default_args;
$filename = $this->wrapper_document->get_filename( $context, $args );
return $filename;
}
protected function add_filters( $filters ) {
foreach ( $filters as $filter ) {
$filter = $this->normalize_filter_args( $filter );
add_filter( $filter['hook_name'], $filter['callback'], $filter['priority'], $filter['accepted_args'] );
}
}
protected function remove_filters( $filters ) {
foreach ( $filters as $filter ) {
$filter = $this->normalize_filter_args( $filter );
remove_filter( $filter['hook_name'], $filter['callback'], $filter['priority'] );
}
}
protected function normalize_filter_args( $filter ) {
$filter = array_values( $filter );
$hook_name = $filter[0];
$callback = $filter[1];
$priority = isset( $filter[2] ) ? $filter[2] : 10;
$accepted_args = isset( $filter[3] ) ? $filter[3] : 1;
return compact( 'hook_name', 'callback', 'priority', 'accepted_args' );
}
}
endif; // class_exists

View File

@@ -0,0 +1,195 @@
<?php
namespace WPO\WC\PDF_Invoices\Documents;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Document_Number' ) ) :
class Document_Number {
/**
* The raw, unformatted number
* @var int
*/
public $number;
/**
* Document number formatted for display
* @var String
*/
public $formatted_number;
/**
* Number prefix
* @var string
*/
public $prefix;
/**
* Number suffix
* @var string
*/
public $suffix;
/**
* Document Type
* @var string
*/
public $document_type;
/**
* Order ID
* @var int
*/
public $order_id;
/**
* Zeros padding (total number of digits including leading zeros)
* @var int
*/
public $padding;
public function __construct( $number, $settings = array(), $document = null, $order = null ) {
$number = apply_filters( 'wpo_wcpdf_raw_document_number', $number, $settings, $document, $order );
if ( !is_array( $number ) && !empty( $number ) ) {
// we're creating a new number with settings as passed
$this->number = $number;
foreach ($settings as $key => $value) {
$this->{$key} = $value;
}
if ( !isset( $this->formatted_number ) ) {
$this->apply_formatting( $document, ( !empty( $document->order ) ? $document->order : $order ) );
}
} elseif ( is_array( $number ) ) {
// loaded with full number data
foreach ($number as $key => $value) {
$this->{$key} = $value;
}
}
if (!empty($document)) {
$this->document_type = $document->get_type();
}
if (!empty($order)) {
$this->order_id = $order->get_id();
}
}
public function __toString() {
return (string) $this->get_formatted();
}
public function get_formatted() {
$formatted_number = isset( $this->formatted_number ) ? $this->formatted_number : '';
$formatted_number = apply_filters( 'wpo_wcpdf_formatted_document_number', $formatted_number, $this, $this->document_type, $this->order_id );
return $formatted_number;
}
public function get_plain() {
return $this->number;
}
public function apply_formatting( $document, $order ) {
if ( empty( $document ) || empty( $order ) ) {
$this->formatted_number = $this->number;
return;
}
// load plain number
$number = $this->number;
// get dates
$order_date = $order->get_date_created();
// order date can be empty when order is being saved, fallback to current time
if ( empty( $order_date ) && function_exists('wc_string_to_datetime') ) {
$order_date = wc_string_to_datetime( date_i18n('Y-m-d H:i:s') );
}
$document_date = $document->get_date();
// fallback to order date if no document date available
if (empty($document_date)) {
$document_date = $order_date;
}
// get format settings
$formats = array(
'prefix' => $this->prefix,
'suffix' => $this->suffix,
);
// load replacement values
$order_year = $order_date->date_i18n( 'Y' );
$order_month = $order_date->date_i18n( 'm' );
$order_day = $order_date->date_i18n( 'd' );
$document_year = $document_date->date_i18n( 'Y' );
$document_month = $document_date->date_i18n( 'm' );
$document_day = $document_date->date_i18n( 'd' );
$order_number = is_callable( array( $order, 'get_order_number' ) ) ? $order->get_order_number() : '';
// make replacements
foreach ( $formats as $key => $value ) {
if ( empty( $value ) ) {
continue;
}
$value = str_replace( '[order_year]', $order_year, $value );
$value = str_replace( '[order_month]', $order_month, $value );
$value = str_replace( '[order_day]', $order_day, $value );
$value = str_replace( "[{$document->slug}_year]", $document_year, $value );
$value = str_replace( "[{$document->slug}_month]", $document_month, $value );
$value = str_replace( "[{$document->slug}_day]", $document_day, $value );
$value = str_replace( '[order_number]', $order_number, $value );
// replace date tag in the form [invoice_date="{$date_format}"] or [order_date="{$date_format}"]
$date_types = array( 'order', $document->slug );
foreach ( $date_types as $date_type ) {
if ( false !== strpos( $value, "[{$date_type}_date=" ) ) {
preg_match_all( "/\[{$date_type}_date=\"(.*?)\"\]/", $value, $document_date_tags );
if ( ! empty( $document_date_tags[1] ) ) {
foreach ( $document_date_tags[1] as $match_id => $date_format ) {
if ( 'order' === $date_type ) {
$value = str_replace( $document_date_tags[0][$match_id], $order_date->date_i18n( $date_format ), $value );
} else {
$value = str_replace( $document_date_tags[0][$match_id], $document_date->date_i18n( $date_format ), $value );
}
}
}
}
}
$formats[$key] = $value;
}
// Padding
$padding_string = '';
if ( function_exists('ctype_digit') ) { // requires the Ctype extension
if ( ctype_digit( (string) $this->padding ) ) {
$padding_string = (string) $this->padding;
}
} elseif ( !empty( $this->padding ) ) {
$padding_string = (string) absint($this->padding);
}
if ( !empty( $padding_string ) ) {
$number = sprintf('%0'.$padding_string.'d', $number);
}
// Add prefix & suffix
$this->formatted_number = $formats['prefix'] . $number . $formats['suffix'] ;
// Apply filters and store
$this->formatted_number = apply_filters( 'wpo_wcpdf_format_document_number', $this->formatted_number, $this, $document, $order );
return $this->formatted_number;
}
public function to_array() {
return (array) $this;
}
}
endif; // class_exists

View File

@@ -0,0 +1,670 @@
<?php
namespace WPO\WC\PDF_Invoices\Documents;
use WPO\WC\PDF_Invoices\Updraft_Semaphore_3_0 as Semaphore;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Invoice' ) ) :
/**
* Invoice Document
*/
class Invoice extends Order_Document_Methods {
public $type;
public $title;
public $icon;
public $lock_name;
public $lock_context;
public $lock_time;
public $lock_retries;
public $output_formats;
/**
* Init/load the order object.
*
* @param int|object|WC_Order $order Order to init.
*/
public function __construct( $order = 0 ) {
// set properties
$this->type = 'invoice';
$this->title = __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' );
$this->icon = WPO_WCPDF()->plugin_url() . "/assets/images/invoice.svg";
// semaphore
$this->lock_name = "wpo_wcpdf_{$this->slug}_number_lock";
$this->lock_context = array( 'source' => "wpo-wcpdf-{$this->type}-semaphore" );
$this->lock_time = apply_filters( "wpo_wcpdf_{$this->type}_number_lock_time", 2 );
$this->lock_retries = apply_filters( "wpo_wcpdf_{$this->type}_number_lock_retries", 0 );
// call parent constructor
parent::__construct( $order );
// output formats (placed after parent construct to override the abstract default)
$this->output_formats = apply_filters( "wpo_wcpdf_{$this->type}_output_formats", array( 'pdf', 'ubl' ), $this );
}
public function use_historical_settings() {
$document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
// this setting is inverted on the frontend so that it needs to be actively/purposely enabled to be used
if (!empty($document_settings) && isset($document_settings['use_latest_settings'])) {
$use_historical_settings = false;
} else {
$use_historical_settings = true;
}
return apply_filters( 'wpo_wcpdf_document_use_historical_settings', $use_historical_settings, $this );
}
public function storing_settings_enabled() {
return apply_filters( 'wpo_wcpdf_document_store_settings', true, $this );
}
public function get_title() {
// override/not using $this->title to allow for language switching!
return apply_filters( "wpo_wcpdf_{$this->slug}_title", __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' ), $this );
}
public function init() {
// save settings
$this->save_settings();
if ( isset( $this->settings['display_date'] ) && $this->settings['display_date'] == 'order_date' && !empty( $this->order ) ) {
$this->set_date( $this->order->get_date_created() );
$this->set_display_date( 'order_date' );
} elseif( empty( $this->get_date() ) ) {
$this->set_date( current_time( 'timestamp', true ) );
$this->set_display_date( 'invoice_date' );
}
$this->init_number();
do_action( 'wpo_wcpdf_init_document', $this );
}
public function exists() {
return !empty( $this->data['number'] );
}
public function init_number() {
$logger = isset( $this->settings['log_number_generation'] ) ? [ wc_get_logger() ] : [];
$lock = new Semaphore( $this->lock_name, $this->lock_time, $logger, $this->lock_context );
$invoice_number = null;
if ( $lock->lock( $this->lock_retries ) ) {
try {
// If a third-party plugin claims to generate invoice numbers, trigger this instead
if ( apply_filters( 'woocommerce_invoice_number_by_plugin', false ) || apply_filters( 'wpo_wcpdf_external_invoice_number_enabled', false, $this ) ) {
$invoice_number = apply_filters( 'woocommerce_generate_invoice_number', null, $this->order );
$invoice_number = apply_filters( 'wpo_wcpdf_external_invoice_number', $invoice_number, $this );
} elseif ( isset( $this->settings['display_number'] ) && $this->settings['display_number'] == 'order_number' && ! empty( $this->order ) ) {
$invoice_number = $this->order->get_order_number();
}
if ( ! empty( $invoice_number ) ) { // overridden by plugin or set to order number
if ( ! is_numeric( $invoice_number ) && ! ( $invoice_number instanceof Document_Number ) ) {
// invoice number is not numeric, treat as formatted
// try to extract meaningful number data
$formatted_number = $invoice_number;
$number = (int) preg_replace( '/\D/', '', $invoice_number );
$invoice_number = compact( 'number', 'formatted_number' );
}
} else {
$number_store = $this->get_sequential_number_store();
$invoice_number = $number_store->increment( intval( $this->order_id ), $this->get_date()->date_i18n( 'Y-m-d H:i:s' ) );
}
if ( ! is_null( $invoice_number ) ) {
$this->set_number( $invoice_number );
}
} catch ( \Exception $e ) {
$lock->log( $e, 'critical' );
} catch ( \Error $e ) {
$lock->log( $e, 'critical' );
}
$lock->release();
} else {
$lock->log( "Couldn't get the Invoice Number lock!", 'critical' );
}
return $invoice_number;
}
public function get_filename( $context = 'download', $args = array() ) {
$order_count = isset($args['order_ids']) ? count($args['order_ids']) : 1;
$name = _n( 'invoice', 'invoices', $order_count, 'woocommerce-pdf-invoices-packing-slips' );
if ( $order_count == 1 ) {
if ( isset( $this->settings['display_number'] ) && $this->settings['display_number'] == 'invoice_number' ) {
$suffix = (string) $this->get_number();
} else {
if ( empty( $this->order ) && isset( $args['order_ids'][0] ) ) {
$order = wc_get_order( $args['order_ids'][0] );
$suffix = is_callable( array( $order, 'get_order_number' ) ) ? $order->get_order_number() : '';
} else {
$suffix = is_callable( array( $this->order, 'get_order_number' ) ) ? $this->order->get_order_number() : '';
}
}
// ensure unique filename in case suffix was empty
if ( empty( $suffix ) ) {
if ( ! empty( $this->order_id ) ) {
$suffix = $this->order_id;
} elseif ( ! empty( $args['order_ids'] ) && is_array( $args['order_ids'] ) ) {
$suffix = reset( $args['order_ids'] );
} else {
$suffix = uniqid();
}
}
} else {
$suffix = date( 'Y-m-d' ); // 2020-11-11
}
// get filename
$output_format = ! empty( $args['output'] ) ? esc_attr( $args['output'] ) : 'pdf';
$filename = $name . '-' . $suffix . $this->get_output_format_extension( $output_format );
// Filter filename
$order_ids = isset( $args['order_ids'] ) ? $args['order_ids'] : array( $this->order_id );
$filename = apply_filters( 'wpo_wcpdf_filename', $filename, $this->get_type(), $order_ids, $context );
// sanitize filename (after filters to prevent human errors)!
return sanitize_file_name( $filename );
}
/**
* Initialise settings
*/
public function init_settings() {
do_action( "wpo_wcpdf_before_{$this->type}_init_settings", $this );
foreach ( $this->output_formats as $output_format ) {
$settings_fields = array();
switch ( $output_format ) {
default:
case 'pdf':
$page = $option_group = $option_name = "wpo_wcpdf_documents_settings_{$this->get_type()}";
$settings_fields = apply_filters( "wpo_wcpdf_settings_fields_documents_{$this->get_type()}", $this->get_pdf_settings_fields( $option_name ), $page, $option_group, $option_name ); // legacy filter
break;
case 'ubl':
$page = $option_group = $option_name = "wpo_wcpdf_documents_settings_{$this->get_type()}_{$output_format}";
$settings_fields = $this->get_ubl_settings_fields( $option_name );
break;
}
if ( ! empty( $settings_fields ) ) {
// allow plugins to alter settings fields
$settings_fields = apply_filters( "wpo_wcpdf_settings_fields_documents_{$this->type}_{$output_format}", $settings_fields, $page, $option_group, $option_name, $this );
WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
}
}
do_action( "wpo_wcpdf_after_{$this->type}_init_settings", $this );
}
/**
* PDF settings fields
*/
public function get_pdf_settings_fields( $option_name ) {
$settings_fields = array(
array(
'type' => 'section',
'id' => $this->type,
'title' => '',
'callback' => 'section',
),
array(
'type' => 'setting',
'id' => 'enabled',
'title' => __( 'Enable', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'enabled',
)
),
array(
'type' => 'setting',
'id' => 'attach_to_email_ids',
'title' => __( 'Attach to:', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'multiple_checkboxes',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'attach_to_email_ids',
'fields_callback' => array( $this, 'get_wc_emails' ),
/* translators: directory path */
'description' => !is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? '<span class="wpo-warning">' . sprintf( __( 'It looks like the temp folder (<code>%s</code>) is not writable, check the permissions for this folder! Without having write access to this folder, the plugin will not be able to email invoices.', 'woocommerce-pdf-invoices-packing-slips' ), WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ).'</span>':'',
)
),
array(
'type' => 'setting',
'id' => 'disable_for_statuses',
'title' => __( 'Disable for:', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'disable_for_statuses',
'options_callback' => 'wc_get_order_statuses',
'multiple' => true,
'enhanced_select' => true,
'placeholder' => __( 'Select one or more statuses', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'display_shipping_address',
'title' => __( 'Display shipping address', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'display_shipping_address',
'options' => array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'when_different'=> __( 'Only when different from billing address' , 'woocommerce-pdf-invoices-packing-slips' ),
'always' => __( 'Always' , 'woocommerce-pdf-invoices-packing-slips' ),
),
// 'description' => __( 'Display shipping address (in addition to the default billing address) if different from billing address', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'display_email',
'title' => __( 'Display email address', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'display_email',
)
),
array(
'type' => 'setting',
'id' => 'display_phone',
'title' => __( 'Display phone number', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'display_phone',
)
),
array(
'type' => 'setting',
'id' => 'display_customer_notes',
'title' => __( 'Display customer notes', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'display_customer_notes',
'store_unchecked' => true,
'default' => 1,
)
),
array(
'type' => 'setting',
'id' => 'display_date',
'title' => __( 'Display invoice date', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'display_date',
'options' => array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'invoice_date' => __( 'Invoice Date' , 'woocommerce-pdf-invoices-packing-slips' ),
'order_date' => __( 'Order Date' , 'woocommerce-pdf-invoices-packing-slips' ),
),
)
),
array(
'type' => 'setting',
'id' => 'due_date',
'title' => __( 'Display due date', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'due_date',
'options' => apply_filters( 'wpo_wcpdf_due_date_options', array(
'' => __( 'No', 'woocommerce-pdf-invoices-packing-slips' ),
'1' => __( '1 day', 'woocommerce-pdf-invoices-packing-slips' ),
'7' => __( '7 days', 'woocommerce-pdf-invoices-packing-slips' ),
'30' => __( '30 days', 'woocommerce-pdf-invoices-packing-slips' ),
), $this->type ),
'description' => __( 'Displays a due date below the order data.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'display_number',
'title' => __( 'Display invoice number', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'display_number',
'options' => array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'invoice_number' => __( 'Invoice Number' , 'woocommerce-pdf-invoices-packing-slips' ),
'order_number' => __( 'Order Number' , 'woocommerce-pdf-invoices-packing-slips' ),
),
'description' => sprintf(
'<strong>%s</strong> %s <a href="https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/invoice-numbers-explained/#why-is-the-pdf-invoice-number-different-from-the-woocommerce-order-number">%s</a>',
__( 'Warning!', 'woocommerce-pdf-invoices-packing-slips' ),
__( 'Using the Order Number as invoice number is not recommended as this may lead to gaps in the invoice number sequence (even when order numbers are sequential).', 'woocommerce-pdf-invoices-packing-slips' ),
__( 'More information', 'woocommerce-pdf-invoices-packing-slips' )
),
)
),
array(
'type' => 'setting',
'id' => 'next_invoice_number',
'title' => __( 'Next invoice number (without prefix/suffix etc.)', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'next_number_edit',
'section' => $this->type,
'args' => array(
'store_callback' => array( $this, 'get_sequential_number_store' ),
'size' => '10',
'description' => __( 'This is the number that will be used for the next document. By default, numbering starts from 1 and increases for every new document. Note that if you override this and set it lower than the current/highest number, this could create duplicate numbers!', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'number_format',
'title' => __( 'Number format', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'multiple_text_input',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'number_format',
'fields' => array(
'prefix' => array(
'label' => __( 'Prefix' , 'woocommerce-pdf-invoices-packing-slips' ),
'size' => 20,
'description' => __( 'If set, this value will be used as number prefix.' , 'woocommerce-pdf-invoices-packing-slips' ) . ' ' . sprintf(
/* translators: 1. document type, 2-3 placeholders */
__( 'You can use the %1$s year and/or month with the %2$s or %3$s placeholders respectively.', 'woocommerce-pdf-invoices-packing-slips' ),
__( 'invoice', 'woocommerce-pdf-invoices-packing-slips' ), '<strong>[invoice_year]</strong>', '<strong>[invoice_month]</strong>'
) . ' ' . __( 'Check the Docs article below to see all the available placeholders for prefix/suffix.', 'woocommerce-pdf-invoices-packing-slips' ),
),
'suffix' => array(
'label' => __( 'Suffix' , 'woocommerce-pdf-invoices-packing-slips' ),
'size' => 20,
'description' => __( 'If set, this value will be used as number suffix.' , 'woocommerce-pdf-invoices-packing-slips' ) . ' ' . sprintf(
/* translators: 1. document type, 2-3 placeholders */
__( 'You can use the %1$s year and/or month with the %2$s or %3$s placeholders respectively.', 'woocommerce-pdf-invoices-packing-slips' ),
__( 'invoice', 'woocommerce-pdf-invoices-packing-slips' ), '<strong>[invoice_year]</strong>', '<strong>[invoice_month]</strong>'
) . ' ' . __( 'Check the Docs article below to see all the available placeholders for prefix/suffix.', 'woocommerce-pdf-invoices-packing-slips' ),
),
'padding' => array(
'label' => __( 'Padding' , 'woocommerce-pdf-invoices-packing-slips' ),
'size' => 20,
'type' => 'number',
/* translators: document type */
'description' => sprintf( __( 'Enter the number of digits you want to use as padding. For instance, enter <code>6</code> to display the %s number <code>123</code> as <code>000123</code>, filling it with zeros until the number set as padding is reached.' , 'woocommerce-pdf-invoices-packing-slips' ), __( 'invoice', 'woocommerce-pdf-invoices-packing-slips' ) ),
),
),
/* translators: document type */
'description' => __( 'For more information about setting up the number format and see the available placeholders for the prefix and suffix, check this article:', 'woocommerce-pdf-invoices-packing-slips' ) . sprintf( ' <a href="https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/number-format-explained/" target="_blank">%s</a>', __( 'Number format explained', 'woocommerce-pdf-invoices-packing-slips') ) . '.<br><br>'. sprintf( __( '<strong>Note</strong>: Changes made to the number format will only be reflected on new orders. Also, if you have already created a custom %s number format with a filter, the above settings will be ignored.', 'woocommerce-pdf-invoices-packing-slips' ), __( 'invoice', 'woocommerce-pdf-invoices-packing-slips' ) ),
)
),
array(
'type' => 'setting',
'id' => 'reset_number_yearly',
'title' => __( 'Reset invoice number yearly', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'reset_number_yearly',
)
),
array(
'type' => 'setting',
'id' => 'log_number_generation',
'title' => __( 'Log invoice number generation', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'log_number_generation',
'description' => sprintf(
/* translators: here link */
__( 'Enables the invoice number generation logs %s. Helpful for debugging numbering issues.', 'woocommerce-pdf-invoices-packing-slips' ),
'<a href="'.esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) ).'">'.__( 'here', 'woocommerce-pdf-invoices-packing-slips' ).'</a>'
),
)
),
array(
'type' => 'setting',
'id' => 'my_account_buttons',
'title' => __( 'Allow My Account invoice download', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'my_account_buttons',
'options' => array(
'available' => __( 'Only when an invoice is already created/emailed' , 'woocommerce-pdf-invoices-packing-slips' ),
'custom' => __( 'Only for specific order statuses (define below)' , 'woocommerce-pdf-invoices-packing-slips' ),
'always' => __( 'Always' , 'woocommerce-pdf-invoices-packing-slips' ),
'never' => __( 'Never' , 'woocommerce-pdf-invoices-packing-slips' ),
),
'custom' => array(
'type' => 'multiple_checkboxes',
'args' => array(
'option_name' => $option_name,
'id' => 'my_account_restrict',
'fields_callback' => array( $this, 'get_wc_order_status_list' ),
),
),
)
),
array(
'type' => 'setting',
'id' => 'invoice_number_column',
'title' => __( 'Enable invoice number column in the orders list', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'invoice_number_column',
)
),
array(
'type' => 'setting',
'id' => 'invoice_date_column',
'title' => __( 'Enable invoice date column in the orders list', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'invoice_date_column',
)
),
array(
'type' => 'setting',
'id' => 'invoice_number_search',
'title' => __( 'Enable invoice number search in the orders list', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'invoice_number_search',
'description' => __( 'Can potentially slow down the search process.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'disable_free',
'title' => __( 'Disable for free orders', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'disable_free',
/* translators: zero number */
'description' => sprintf(__( "Disable document when the order total is %s", 'woocommerce-pdf-invoices-packing-slips' ), function_exists('wc_price') ? wc_price( 0 ) : 0 ),
)
),
array(
'type' => 'setting',
'id' => 'mark_printed',
'title' => __( 'Mark as printed', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'mark_printed',
'options' => array_merge(
[
'manually' => __( 'Manually', 'woocommerce-pdf-invoices-packing-slips' ),
],
apply_filters( 'wpo_wcpdf_document_triggers', [
'single' => __( 'On single order action', 'woocommerce-pdf-invoices-packing-slips' ),
'bulk' => __( 'On bulk order action', 'woocommerce-pdf-invoices-packing-slips' ),
'my_account' => __( 'On my account', 'woocommerce-pdf-invoices-packing-slips' ),
'email_attachment' => __( 'On email attachment', 'woocommerce-pdf-invoices-packing-slips' ),
'document_data' => __( 'On order document data (number and/or date set manually)', 'woocommerce-pdf-invoices-packing-slips' ),
] )
),
'multiple' => true,
'enhanced_select' => true,
'description' => __( 'Allows you to mark the document as printed, manually (in the order page) or automatically (based on the document creation context you have selected).', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'unmark_printed',
'title' => __( 'Unmark as printed', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'unmark_printed',
'description' => __( 'Adds a link in the order page to allow to remove the printed mark.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'use_latest_settings',
'title' => __( 'Always use most current settings', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type,
'args' => array(
'option_name' => $option_name,
'id' => 'use_latest_settings',
'description' => __( "When enabled, the document will always reflect the most current settings (such as footer text, document name, etc.) rather than using historical settings.", 'woocommerce-pdf-invoices-packing-slips' )
. "<br>"
. __( "<strong>Caution:</strong> enabling this will also mean that if you change your company name or address in the future, previously generated documents will also be affected.", 'woocommerce-pdf-invoices-packing-slips' ),
)
),
);
// remove/rename some fields when invoice number is controlled externally
if ( apply_filters( 'woocommerce_invoice_number_by_plugin', false ) ) {
$remove_settings = array( 'next_invoice_number', 'number_format', 'reset_number_yearly' );
foreach ( $settings_fields as $key => $settings_field ) {
if ( in_array( $settings_field['id'], $remove_settings ) ) {
unset( $settings_fields[$key] );
} elseif ( $settings_field['id'] == 'display_number' ) {
// alternate description for invoice number
$invoice_number_desc = __( 'Invoice numbers are created by a third-party extension.', 'woocommerce-pdf-invoices-packing-slips' );
if ( $config_link = apply_filters( 'woocommerce_invoice_number_configuration_link', null ) ) {
/* translators: link */
$invoice_number_desc .= ' '.sprintf(__( 'Configure it <a href="%s">here</a>.', 'woocommerce-pdf-invoices-packing-slips' ), esc_attr( $config_link ) );
}
$settings_fields[$key]['args']['description'] = '<i>'.$invoice_number_desc.'</i>';
}
}
}
return apply_filters( "wpo_wcpdf_{$this->type}_pdf_settings_fields", $settings_fields, $option_name, $this );
}
/**
* UBL settings fields
*/
public function get_ubl_settings_fields( $option_name ) {
$settings_fields = array(
array(
'type' => 'section',
'id' => $this->type.'_ubl',
'title' => '',
'callback' => 'section',
),
array(
'type' => 'setting',
'id' => 'enabled',
'title' => __( 'Enable', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type.'_ubl',
'args' => array(
'option_name' => $option_name,
'id' => 'enabled',
)
),
array(
'type' => 'setting',
'id' => 'attach_to_email_ids',
'title' => __( 'Attach to:', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'multiple_checkboxes',
'section' => $this->type.'_ubl',
'args' => array(
'option_name' => $option_name,
'id' => 'attach_to_email_ids',
'fields_callback' => array( $this, 'get_wc_emails' ),
/* translators: directory path */
'description' => ! is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? '<span class="wpo-warning">' . sprintf( __( 'It looks like the temp folder (<code>%s</code>) is not writable, check the permissions for this folder! Without having write access to this folder, the plugin will not be able to email invoices.', 'woocommerce-pdf-invoices-packing-slips' ), WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ).'</span>':'',
)
),
array(
'type' => 'setting',
'id' => 'include_encrypted_pdf',
'title' => __( 'Include encrypted PDF:', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => $this->type.'_ubl',
'args' => array(
'option_name' => $option_name,
'id' => 'include_encrypted_pdf',
'description' => __( 'Include the PDF Invoice file encrypted in the UBL file.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
);
return apply_filters( "wpo_wcpdf_{$this->type}_ubl_settings_fields", $settings_fields, $option_name, $this );
}
/**
* Document number title
*/
public function get_number_title() {
$number_title = __( 'Invoice Number:', 'woocommerce-pdf-invoices-packing-slips' );
return apply_filters( "wpo_wcpdf_{$this->slug}_number_title", $number_title, $this );
}
/**
* Document date title
*/
public function get_date_title() {
$date_title = __( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' );
return apply_filters( "wpo_wcpdf_{$this->slug}_date_title", $date_title, $this );
}
}
endif; // class_exists

View File

@@ -0,0 +1,198 @@
<?php
namespace WPO\WC\PDF_Invoices\Documents;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Packing_Slip' ) ) :
/**
* Packing Slip Document
*/
class Packing_Slip extends Order_Document_Methods {
/**
* Init/load the order object.
*
* @param int|object|WC_Order $order Order to init.
*/
public function __construct( $order = 0 ) {
// set properties
$this->type = 'packing-slip';
$this->title = __( 'Packing Slip', 'woocommerce-pdf-invoices-packing-slips' );
$this->icon = WPO_WCPDF()->plugin_url() . "/assets/images/packing-slip.svg";
// call parent constructor
parent::__construct( $order );
// output formats (placed after parent construct to override the abstract default)
$this->output_formats = apply_filters( "wpo_wcpdf_{$this->type}_output_formats", array( 'pdf' ), $this );
}
public function get_title() {
// override/not using $this->title to allow for language switching!
return apply_filters( "wpo_wcpdf_{$this->slug}_title", __( 'Packing Slip', 'woocommerce-pdf-invoices-packing-slips' ), $this );
}
public function get_filename( $context = 'download', $args = array() ) {
$order_count = isset($args['order_ids']) ? count($args['order_ids']) : 1;
$name = _n( 'packing-slip', 'packing-slips', $order_count, 'woocommerce-pdf-invoices-packing-slips' );
if ( $order_count == 1 ) {
if ( isset( $this->settings['display_number'] ) ) {
$suffix = (string) $this->get_number();
} else {
if ( empty( $this->order ) && isset( $args['order_ids'] ) ) {
$order = wc_get_order( $args['order_ids'][0] );
$suffix = is_callable( array( $order, 'get_order_number' ) ) ? $order->get_order_number() : '';
} else {
$suffix = is_callable( array( $this->order, 'get_order_number' ) ) ? $this->order->get_order_number() : '';
}
}
} else {
$suffix = date( 'Y-m-d' ); // 2020-11-11
}
// get filename
$output_format = ! empty( $args['output'] ) ? esc_attr( $args['output'] ) : 'pdf';
$filename = $name . '-' . $suffix . $this->get_output_format_extension( $output_format );
// Filter filename
$order_ids = isset( $args['order_ids'] ) ? $args['order_ids'] : array( $this->order_id );
$filename = apply_filters( 'wpo_wcpdf_filename', $filename, $this->get_type(), $order_ids, $context );
// sanitize filename (after filters to prevent human errors)!
return sanitize_file_name( $filename );
}
public function init_settings() {
// Register settings.
$page = $option_group = $option_name = 'wpo_wcpdf_documents_settings_packing-slip';
$settings_fields = array(
array(
'type' => 'section',
'id' => 'packing_slip',
'title' => '',
'callback' => 'section',
),
array(
'type' => 'setting',
'id' => 'enabled',
'title' => __( 'Enable', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'packing_slip',
'args' => array(
'option_name' => $option_name,
'id' => 'enabled',
)
),
array(
'type' => 'setting',
'id' => 'display_billing_address',
'title' => __( 'Display billing address', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => 'packing_slip',
'args' => array(
'option_name' => $option_name,
'id' => 'display_billing_address',
'options' => array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'when_different'=> __( 'Only when different from shipping address' , 'woocommerce-pdf-invoices-packing-slips' ),
'always' => __( 'Always' , 'woocommerce-pdf-invoices-packing-slips' ),
),
// 'description' => __( 'Display billing address (in addition to the default shipping address) if different from shipping address', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'display_email',
'title' => __( 'Display email address', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'packing_slip',
'args' => array(
'option_name' => $option_name,
'id' => 'display_email',
)
),
array(
'type' => 'setting',
'id' => 'display_phone',
'title' => __( 'Display phone number', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'packing_slip',
'args' => array(
'option_name' => $option_name,
'id' => 'display_phone',
)
),
array(
'type' => 'setting',
'id' => 'display_customer_notes',
'title' => __( 'Display customer notes', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'packing_slip',
'args' => array(
'option_name' => $option_name,
'id' => 'display_customer_notes',
'store_unchecked' => true,
'default' => 1,
)
),
);
if ( ! function_exists( 'WPO_WCPDF_Pro' ) ) {
ob_start();
?>
<div class="notice notice-info inline">
<p><a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/" target="_blank"><?php _e( 'Upgrade to our Professional extension to attach packing slips to any email!', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></p>
</div>
<?php
$html = ob_get_clean();
$pro_notice = array(
array(
'type' => 'setting',
'id' => 'attach_to_email_ids',
'title' => __( 'Attach to:', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'html_section',
'section' => 'packing_slip',
'args' => array(
'option_name' => $option_name,
'id' => 'attach_to_email_ids',
'html' => $html,
)
),
);
$settings_fields = WPO_WCPDF()->settings->move_setting_after_id( $settings_fields, $pro_notice, 'enabled' );
}
// allow plugins to alter settings fields
$settings_fields = apply_filters( 'wpo_wcpdf_settings_fields_documents_packing_slip', $settings_fields, $page, $option_group, $option_name );
WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
return;
}
/**
* Document number title
*/
public function get_number_title() {
$number_title = __( 'Packing Slip Number:', 'woocommerce-pdf-invoices-packing-slips' );
return apply_filters( "wpo_wcpdf_{$this->slug}_number_title", $number_title, $this );
}
/**
* Document date title
*/
public function get_date_title() {
$date_title = __( 'Packing Slip Date:', 'woocommerce-pdf-invoices-packing-slips' );
return apply_filters( "wpo_wcpdf_{$this->slug}_date_title", $date_title, $this );
}
}
endif; // class_exists

View File

@@ -0,0 +1,198 @@
<?php
namespace WPO\WC\PDF_Invoices\Documents;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Sequential_Number_Store' ) ) :
/**
* Class handling database interaction for sequential numbers
*/
class Sequential_Number_Store {
/**
* WordPress database object
* @var object
*/
private $wpdb;
/**
* Name of the number store (used for table_name)
* @var string
*/
public $store_name;
/**
* Number store method, either 'auto_increment' or 'calculate'
* @var string
*/
public $method;
/**
* Name of the table that stores the number sequence (including the wp_wcpdf_ table prefix)
* @var string
*/
public $table_name;
/**
* If table name not found in database, is new table
* @var bool
*/
public $is_new = false;
public function __construct( $store_name, $method = 'auto_increment' ) {
global $wpdb;
$this->wpdb = $wpdb;
$this->store_name = $store_name;
$this->method = $method;
$this->table_name = apply_filters( "wpo_wcpdf_number_store_table_name", "{$this->wpdb->prefix}wcpdf_{$this->store_name}", $this->store_name, $this->method ); // e.g. wp_wcpdf_invoice_number
$this->init();
}
public function init() {
// check if table exists
if( ! $this->store_name_exists() ) {
$this->is_new = true;
} else {
// check calculated_number column if using 'calculate' method
if ( $this->method == 'calculate' ) {
$column_exists = $this->wpdb->get_var("SHOW COLUMNS FROM `{$this->table_name}` LIKE 'calculated_number'");
if ( empty( $column_exists ) ) {
$this->wpdb->query("ALTER TABLE {$this->table_name} ADD calculated_number int (16)");
}
}
return; // no further business
}
// create table (in case of concurrent requests, this does no harm if it already exists)
$charset_collate = $this->wpdb->get_charset_collate();
// dbDelta is a sensitive kid, so we omit indentation
$sql = "CREATE TABLE {$this->table_name} (
id int(16) NOT NULL AUTO_INCREMENT,
order_id int(16),
date datetime DEFAULT '1000-01-01 00:00:00' NOT NULL,
calculated_number int (16),
PRIMARY KEY (id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
// catch mysql errors
wcpdf_catch_db_object_errors( $this->wpdb );
return;
}
/**
* Consume/create the next number and return it
* @param integer $order_id WooCommerce Order ID
* @param string $date Local date, formatted as Y-m-d H:i:s
* @return int Number that was consumed/created
*/
public function increment( $order_id = 0, $date = null ) {
if ( empty( $date ) ) {
$date = get_date_from_gmt( date( 'Y-m-d H:i:s' ) );
}
do_action( 'wpo_wcpdf_before_sequential_number_increment', $this, $order_id, $date );
$data = array(
'order_id' => absint( $order_id ),
'date' => $date,
);
if ( $this->method == 'auto_increment' ) {
$this->wpdb->insert( $this->table_name, $data );
$number = $this->wpdb->insert_id;
} elseif ( $this->method == 'calculate' ) {
$number = $data['calculated_number'] = $this->get_next();
$this->wpdb->insert( $this->table_name, $data );
}
// return generated number
return $number;
}
/**
* Get the number that will be used on the next increment
* @return int next number
*/
public function get_next() {
if ( $this->method == 'auto_increment' ) {
// clear cache first on mysql 8.0+
if ( $this->wpdb->get_var( "SHOW VARIABLES LIKE 'information_schema_stats_expiry'" ) ) {
$this->wpdb->query( "SET SESSION information_schema_stats_expiry = 0" );
}
// get next auto_increment value
$table_status = $this->wpdb->get_row("SHOW TABLE STATUS LIKE '{$this->table_name}'");
$next = $table_status->Auto_increment;
} elseif ( $this->method == 'calculate' ) {
$last_row = $this->wpdb->get_row( "SELECT * FROM {$this->table_name} WHERE id = ( SELECT MAX(id) from {$this->table_name} )" );
if ( empty( $last_row ) ) {
$next = 1;
} elseif ( ! empty( $last_row->calculated_number ) ) {
$next = (int) $last_row->calculated_number + 1;
} else {
$next = (int) $last_row->id + 1;
}
}
return $next;
}
/**
* Set the number that will be used on the next increment
*/
public function set_next( $number = 1 ) {
// delete all rows
$delete = $this->wpdb->query("TRUNCATE TABLE {$this->table_name}");
// set auto_increment
if ( $number > 1 ) {
// if AUTO_INCREMENT is not 1, we need to make sure we have a 'highest value' in case of server restarts
// https://serverfault.com/questions/228690/mysql-auto-increment-fields-resets-by-itself
$highest_number = (int) $number - 1;
$this->wpdb->query( $this->wpdb->prepare( "ALTER TABLE {$this->table_name} AUTO_INCREMENT=%d;", $highest_number ) );
$data = array(
'order_id' => 0,
'date' => get_date_from_gmt( date( 'Y-m-d H:i:s' ) ),
);
if ( $this->method == 'calculate' ) {
$data['calculated_number'] = $highest_number;
}
// after this insert, AUTO_INCREMENT will be equal to $number
$this->wpdb->insert( $this->table_name, $data );
} else {
// simple scenario, no need to insert any rows
$this->wpdb->query( $this->wpdb->prepare( "ALTER TABLE {$this->table_name} AUTO_INCREMENT=%d;", $number ) );
}
}
public function get_last_date( $format = 'Y-m-d H:i:s' ) {
$row = $this->wpdb->get_row( "SELECT * FROM {$this->table_name} WHERE id = ( SELECT MAX(id) from {$this->table_name} )" );
$date = isset( $row->date ) ? $row->date : 'now';
$formatted_date = date( $format, strtotime( $date ) );
return $formatted_date;
}
/**
* @return bool
*/
public function store_name_exists() {
// check if table exists
if ( $this->wpdb->get_var("SHOW TABLES LIKE '{$this->table_name}'") == $this->table_name ) {
return true;
} else {
return false;
}
}
}
endif; // class_exists

View File

@@ -0,0 +1,73 @@
<?php
namespace WPO\WC\PDF_Invoices\Makers;
use Dompdf\Dompdf;
use Dompdf\Options;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Makers\\PDF_Maker' ) ) :
class PDF_Maker {
public $html;
public $settings;
public $document;
public function __construct( $html, $settings = array(), $document = null ) {
$this->html = $html;
$this->document = $document;
$default_settings = array(
'paper_size' => 'A4',
'paper_orientation' => 'portrait',
'font_subsetting' => false,
);
$this->settings = $settings + $default_settings;
}
public function output() {
if ( empty( $this->html ) ) {
return;
}
// set options
$options = new Options( apply_filters( 'wpo_wcpdf_dompdf_options', array(
'tempDir' => WPO_WCPDF()->main->get_tmp_path( 'dompdf' ),
'fontDir' => WPO_WCPDF()->main->get_tmp_path( 'fonts' ),
'fontCache' => WPO_WCPDF()->main->get_tmp_path( 'fonts' ),
'chroot' => $this->get_chroot_paths(),
'logOutputFile' => WPO_WCPDF()->main->get_tmp_path( 'dompdf' ) . "/log.htm",
'defaultFont' => 'dejavu sans',
'isRemoteEnabled' => true,
'isFontSubsettingEnabled' => $this->settings['font_subsetting'],
) ) );
// instantiate and use the dompdf class
$dompdf = new Dompdf( $options );
$dompdf->loadHtml( $this->html );
$dompdf->setPaper( $this->settings['paper_size'], $this->settings['paper_orientation'] );
$dompdf = apply_filters( 'wpo_wcpdf_before_dompdf_render', $dompdf, $this->html, $options, $this->document );
$dompdf->render();
$dompdf = apply_filters( 'wpo_wcpdf_after_dompdf_render', $dompdf, $this->html, $options, $this->document );
return $dompdf->output();
}
private function get_chroot_paths() {
$chroot = array( WP_CONTENT_DIR ); // default
if( $wp_upload_base = WPO_WCPDF()->main->get_wp_upload_base() ) {
$chroot[] = $wp_upload_base;
}
if( $tmp_base = WPO_WCPDF()->main->get_tmp_base() ) {
$chroot[] = $tmp_base;
}
return apply_filters( 'wpo_wcpdf_dompdf_chroot', $chroot );
}
}
endif; // class_exists

View File

@@ -0,0 +1,42 @@
<?php
namespace WPO\WC\PDF_Invoices\Makers;
use WPO\WC\UBL\Exceptions\FileWriteException;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Makers\\UBL_Maker' ) ) :
class UBL_Maker {
protected $tmp_base;
public function write( $filename, $contents ) {
$full_file_name = $this->get_file_path() . $filename;
$status = file_put_contents( $full_file_name, $contents );
if ( false === $status ) {
throw new FileWriteException( 'Error writing UBL file' );
}
return $full_file_name;
}
public function set_file_path( $file_path ) {
$this->tmp_base = $file_path;
}
public function get_file_path() {
if ( ! empty( $this->tmp_base ) ) {
return $this->tmp_base;
}
$this->tmp_base = trailingslashit( WPO_WCPDF()->main->get_tmp_path( 'ubl' ) );
return $this->tmp_base;
}
}
endif; // class_exists

View File

@@ -0,0 +1,721 @@
<?php
namespace WPO\WC\PDF_Invoices\Settings;
use WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings\\Settings_Callbacks' ) ) :
class Settings_Callbacks {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Section null callback.
*
* @return void.
*/
public function section() {
}
/**
* Debug section callback.
*
* @return void.
*/
public function debug_section() {
echo wp_kses_post( __( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'woocommerce-pdf-invoices-packing-slips' ) );
}
/**
* Custom fields section callback.
*
* @return void.
*/
public function custom_fields_section() {
echo wp_kses_post( __( 'These are used for the (optional) footer columns in the <em>Modern (Premium)</em> template, but can also be used for other elements in your custom template' , 'woocommerce-pdf-invoices-packing-slips' ) );
}
/**
* HTML section callback.
*
* @return void.
*/
public function html_section( $args ) {
extract( $this->normalize_settings_args( $args ) );
// output HTML
echo wp_kses_post( $html );
}
/**
* Checkbox callback.
*
* args:
* option_name - name of the main option
* id - key of the setting
* value - value if not 1 (optional)
* default - default setting (optional)
* description - description (optional)
*
* @return void.
*/
public function checkbox( $args ) {
extract( $this->normalize_settings_args( $args ) );
// output checkbox
printf( '<input type="checkbox" id="%1$s" name="%2$s" value="%3$s" %4$s %5$s/>', esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $value ), checked( $value, $current, false ), ! empty( $disabled ) ? 'disabled="disabled"' : '' );
// print store empty input if true
if( $store_unchecked ) {
printf( '<input type="hidden" name="%s[wpo_wcpdf_setting_store_empty][]" value="%s"/>', $option_name, esc_attr( $id ) );
}
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Text input callback.
*
* args:
* option_name - name of the main option
* id - key of the setting
* size - size of the text input (em)
* default - default setting (optional)
* description - description (optional)
* type - type (optional)
*
* @return void.
*/
public function text_input( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( empty( $type ) ) {
$type = 'text';
}
$size = ! empty( $size ) ? sprintf( 'size="%s"', esc_attr( $size ) ) : '';
printf( '<input type="%1$s" id="%2$s" name="%3$s" value="%4$s" %5$s placeholder="%6$s" %7$s/>', esc_attr( $type ), esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $current ), $size, esc_attr( $placeholder ), ! empty( $disabled ) ? 'disabled="disabled"' : '' );
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* URL input callback.
*
* args:
* option_name - name of the main option
* id - key of the setting
* size - size of the text input (em)
* default - default setting (optional)
* description - description (optional)
* type - type (optional)
*
* @return void.
*/
public function url_input( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( empty( $type ) ) {
$type = 'url';
}
$size = ! empty( $size ) ? sprintf( 'size="%s"', esc_attr( $size ) ) : '';
printf( '<input type="%1$s" id="%2$s" name="%3$s" value="%4$s" %5$s placeholder="%6$s" %7$s/>', esc_attr( $type ), esc_attr( $id ), esc_attr( $setting_name ), sanitize_url( $current ), $size, esc_attr( $placeholder ), ! empty( $disabled ) ? 'disabled="disabled"' : '' );
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Combined checkbox & text input callback.
*
* args:
* option_name - name of the main option
* id - key of the setting
* value - value if not 1 (optional)
* default - default setting (optional)
* description - description (optional)
*
* @return void.
*/
public function checkbox_text_input( $args ) {
$args = $this->normalize_settings_args( $args );
extract( $args );
unset( $args['description'] ); // already extracted, should only be used here
// get checkbox
ob_start();
$this->checkbox( $args );
$checkbox = ob_get_clean();
// get text input for insertion in wrapper
$input_args = array(
'id' => $args['text_input_id'],
'default' => isset( $args['text_input_default'] ) ? (string) $args['text_input_default'] : NULL,
'size' => isset( $args['text_input_size'] ) ? $args['text_input_size'] : NULL,
) + $args;
unset( $input_args['current'] );
unset( $input_args['setting_name'] );
ob_start();
$this->text_input( $input_args );
$text_input = ob_get_clean();
if (! empty( $text_input_wrap ) ) {
printf( "{$checkbox} {$text_input_wrap}", $text_input);
} else {
echo "{$checkbox} {$text_input}";
}
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
// Single text option (not part of any settings array)
public function singular_text_element( $args ) {
$option_name = $args['option_name'];
$id = $args['id'];
$size = isset( $args['size'] ) ? $args['size'] : '25';
$class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
$option = get_option( $option_name );
if ( isset( $option ) ) {
$current = $option;
} else {
$current = isset( $args['default'] ) ? $args['default'] : '';
}
printf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', esc_attr( $id ), esc_attr( $option_name ), esc_attr( $current ), esc_attr( $size ), esc_attr( $class ) );
// output description.
if ( isset( $args['description'] ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $args['description'] ) );
}
}
/**
* Textarea callback.
*
* args:
* option_name - name of the main option
* id - key of the setting
* width - width of the text input (em)
* height - height of the text input (lines)
* default - default setting (optional)
* description - description (optional)
*
* @return void.
*/
public function textarea( $args ) {
extract( $this->normalize_settings_args( $args ) );
printf( '<textarea id="%1$s" name="%2$s" cols="%4$s" rows="%5$s" placeholder="%6$s"/>%3$s</textarea>', esc_attr( $id ), esc_attr( $setting_name ), esc_textarea( $current ), esc_attr( $width ), esc_attr( $height ), esc_attr( $placeholder ) );
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Select element callback.
*
* @param array $args Field arguments.
*
* @return void
*/
public function select( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( ! empty( $enhanced_select ) ) {
if ( ! empty( $multiple ) ) {
$setting_name = "{$setting_name}[]";
$multiple = 'multiple=multiple';
} else {
$multiple = '';
}
$placeholder = ! empty( $placeholder ) ? esc_attr( $placeholder ) : '';
$title = ! empty( $title ) ? esc_attr( $title ) : '';
$class = 'wc-enhanced-select wpo-wcpdf-enhanced-select';
$css = 'width:400px';
printf( '<select id="%1$s" name="%2$s" data-placeholder="%3$s" title="%4$s" class="%5$s" style="%6$s" %7$s>', esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $placeholder ), esc_attr( $title ), esc_attr( $class ), esc_attr( $css ), esc_attr( $multiple ) );
} else {
printf( '<select id="%1$s" name="%2$s">', esc_attr( $id ), esc_attr( $setting_name ) );
}
if ( ! empty( $options_callback ) ) {
$options = isset( $options_callback_args ) ? call_user_func_array( $options_callback, $options_callback_args ) : call_user_func( $options_callback );
}
foreach ( $options as $key => $label ) {
if ( ! empty( $multiple ) && is_array( $current ) ) {
$selected = in_array( $key, $current ) ? ' selected="selected"' : '';
printf( '<option value="%s"%s>%s</option>', esc_attr( $key ), esc_attr( $selected ), esc_html( $label ) );
} else {
printf( '<option value="%s"%s>%s</option>', esc_attr( $key ), esc_attr( selected( $current, $key, false ) ), esc_html( $label ) );
}
}
echo '</select>';
if ( ! empty( $custom ) ) {
printf( '<div class="%1$s_custom custom">', esc_attr( $id ) );
if ( is_callable( array( $this, $custom['type'] ) ) ) {
$this->{$custom['type']}( $custom['args'] );
}
echo '</div>';
$custom_option = ! empty( $custom['custom_option'] ) ? $custom['custom_option'] : 'custom';
?>
<script type="text/javascript">
jQuery(document).ready(function($) {
function check_<?php echo esc_attr( $id ); ?>_custom() {
var custom = $('#<?php echo esc_attr( $id ); ?>').val();
if (custom == '<?php echo $custom_option; ?>') {
$( '.<?php echo esc_attr( $id ); ?>_custom').show();
} else {
$( '.<?php echo esc_attr( $id ); ?>_custom').hide();
}
}
check_<?php echo esc_attr( $id ); ?>_custom();
$( '#<?php echo esc_attr( $id ); ?>' ).on( 'change', function() {
check_<?php echo esc_attr( $id ); ?>_custom();
});
});
</script>
<?php
}
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
public function radio_button( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( ! empty( $options_callback ) ) {
$options = isset( $options_callback_args ) ? call_user_func_array( $options_callback, $options_callback_args ) : call_user_func( $options_callback );
}
foreach ( $options as $key => $label ) {
printf( '<input type="radio" class="radio" id="%1$s[%3$s]" name="%2$s" value="%3$s"%4$s />', esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $key ), checked( $current, $key, false ) );
printf( '<label for="%1$s[%3$s]"> %4$s</label><br>', esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $key ), esc_html( $label ) );
}
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Multiple text element callback.
* @param array $args Field arguments.
* @return void
*/
public function multiple_text_input( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( ! empty( $fields_callback ) ) {
$fields = isset( $fields_callback_args ) ? call_user_func_array( $fields_callback, $fields_callback_args ) : call_user_func( $fields_callback );
}
printf( '<table class="%s multiple-text-input">', esc_attr( $id ) );
if ( ! empty( $header ) ) {
echo wp_kses_post( "<tr><td><strong>{$header}</strong>:</td></tr>" );
}
foreach ($fields as $name => $field) {
echo '<tr>';
$size = $field['size'];
$placeholder = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
$field_description = ! empty( $field['description'] ) ? $field['description']: '';
// output field label
if ( isset( $field['label'] ) ) {
printf( '<td class="label"><label for="%1$s_%2$s">%3$s:</label></td>', esc_attr( $id ), esc_attr( $name ), esc_html( $field['label'] ) );
} else {
echo '<td></td>';
}
// output field
$field_current = isset( $current[$name] ) ? $current[$name] : '';
$type = isset( $field['type'] ) ? $field['type'] : 'text';
printf( '<td><input type="%1$s" id="%2$s_%4$s" name="%3$s[%4$s]" value="%5$s" size="%6$s" placeholder="%7$s"/></td>', esc_attr( $type ), esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $name ), esc_attr( $field_current ), esc_attr( $size ), esc_attr( $placeholder ) );
// field description.
if ( ! empty( $field_description ) ) {
echo '<td>' . wc_help_tip( $field_description, true ) . '</td>';
} else {
echo '<td></td>';
}
echo '</tr>';
}
echo "</table>";
// group description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Multiple text element callback.
* @param array $args Field arguments.
* @return void
*/
public function multiple_checkboxes( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( ! empty( $fields_callback ) ) {
$fields = isset( $fields_callback_args ) ? call_user_func_array( $fields_callback, $fields_callback_args ) : call_user_func( $fields_callback );
}
foreach ( $fields as $name => $label ) {
// output checkbox
$field_current = isset( $current[$name] ) ? $current[$name] : '';
printf( '<input type="checkbox" id="%1$s_%3$s" name="%2$s[%3$s]" value="%4$s"%5$s />', esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $name ), esc_attr( $value ), checked( $value, $field_current, false ) );
// output field label
printf( '<label for="%1$s_%2$s">%3$s</label><br>', esc_attr( $id ), esc_attr( $name ), esc_html( $label ) );
}
// output description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Media upload callback.
*
* @param array $args Field arguments.
* @return void
*/
public function media_upload( $args ) {
extract( $this->normalize_settings_args( $args ) );
if( ! empty( $current ) && $attachment = wp_get_attachment_image_src( $current, 'full', false ) ) {
$general_settings = get_option('wpo_wcpdf_settings_general');
$attachment_src = $attachment[0];
$attachment_width = $attachment[1];
$attachment_height = $attachment[2];
// check if we have the height saved on settings
$header_logo_height = !empty( $general_settings['header_logo_height'] ) ? $general_settings['header_logo_height'] : '3cm';
if ( stripos( $header_logo_height, 'mm' ) != false ) {
$in_height = floatval( $header_logo_height )/25.4;
} elseif ( stripos( $header_logo_height, 'cm' ) != false ) {
$in_height = floatval( $header_logo_height )/2.54;
} elseif ( stripos( $header_logo_height, 'in' ) != false ) {
$in_height = floatval( $header_logo_height );
} else {
// don't display resolution
}
/*
* .webp support can be disabled but still showing the image in settings.
* We should add a notice because this will display an error when redering the PDF using DOMPDF.
*/
if ( 'webp' === wp_check_filetype( $attachment_src )['ext'] && ! function_exists( 'imagecreatefromwebp' ) ) {
printf(
'<div class="notice notice-warning inline" style="display:inline-block; width:auto;"><p>%s</p></div>',
wp_kses_post( 'File type <strong>webp</strong> is not supported by your server! Please check your <strong>System Configurations</strong> under the <strong>Advanced</strong> tab.', 'woocommerce-pdf-invoices-packing-slips' )
);
}
printf( '<img src="%1$s" style="display:block" id="img-%2$s" class="media-upload-preview"/>', esc_attr( $attachment_src ), esc_attr( $id ) );
if ( ! empty( $attachment_height ) && ! empty( $in_height ) ) {
$attachment_resolution = round( absint( $attachment_height ) / $in_height );
printf(
'<div class="attachment-resolution"><p class="description">%s: %sdpi</p></div>',
esc_html__( 'Image resolution', 'woocommerce-pdf-invoices-packing-slips' ),
$attachment_resolution
);
// warn the user if the image is unnecessarily large
if ( $attachment_resolution > 600 ) {
printf(
'<div class="attachment-resolution-warning notice notice-warning inline"><p>%s</p></div>',
esc_html__( 'The image resolution exceeds the recommended maximum of 600dpi. This will unnecessarily increase the size of your PDF files and could negatively affect performance.', 'woocommerce-pdf-invoices-packing-slips' )
);
}
}
printf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span> ', esc_attr( $id ), esc_attr( $remove_button_text ) );
}
printf( '<input id="%1$s" name="%2$s" type="hidden" value="%3$s" data-settings_callback_args="%4$s" data-ajax_nonce="%5$s" class="media-upload-id"/>', esc_attr( $id ), esc_attr( $setting_name ), esc_attr( $current ), esc_attr( json_encode( $args ) ), wp_create_nonce( "wpo_wcpdf_get_media_upload_setting_html" ) );
printf( '<span class="button wpo_upload_image_button %4$s" data-uploader_title="%1$s" data-uploader_button_text="%2$s" data-remove_button_text="%3$s" data-input_id="%4$s">%2$s</span>', esc_attr( $uploader_title ), esc_attr( $uploader_button_text ), esc_attr( $remove_button_text ), esc_attr( $id ) );
// Displays option description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Next document number edit callback.
*
* @param array $args Field arguments.
*/
public function next_number_edit( $args ) {
extract( $args ); // $store, $size, $description
if ( ! empty( $store_callback ) ) {
$store = isset( $store_callback_args ) ? call_user_func_array( $store_callback, $store_callback_args ) : call_user_func( $store_callback );
}
// Sequential_Number_Store object
if( is_object( $store ) ) {
$next_number = $store->get_next();
$store = $store->store_name;
// legacy
} else {
$number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
$number_store = new Sequential_Number_Store( $store, $number_store_method );
$next_number = $number_store->get_next();
}
$nonce = wp_create_nonce( "wpo_wcpdf_next_{$store}" );
printf(
'<input id="next_%1$s" class="next-number-input" type="number" size="%2$s" value="%3$s" disabled="disabled" data-store="%1$s" data-nonce="%4$s"/> <span class="edit-next-number dashicons dashicons-edit"></span><span class="save-next-number button secondary" style="display:none;">%5$s</span>',
esc_attr( $store ),
esc_attr( $size ),
esc_attr( $next_number ),
esc_attr( $nonce ),
esc_html__( 'Save', 'woocommerce-pdf-invoices-packing-slips' )
);
// Displays option description.
if ( ! empty( $description ) ) {
printf( '<p class="description">%s</p>', wp_kses_post( $description ) );
}
}
/**
* Wrapper function to create tabs for settings in different languages
* @param array $args
* @return void
*/
public function i18n_wrap ( $args ) {
extract( $this->normalize_settings_args( $args ) );
if ( $languages = $this->get_languages() ) {
printf( '<div id="%s-%s-translations" class="translations">', esc_attr( $option_name ), esc_attr( $id ) );
?>
<ul>
<?php foreach ( $languages as $lang_code => $language_name ) {
$translation_id = "{$option_name}_{$id}_{$lang_code}";
printf( '<li><a href="#%s">%s</a></li>', esc_attr( $translation_id ), esc_html( $language_name ) );
}
?>
</ul>
<?php foreach ( $languages as $lang_code => $language_name ) {
$translation_id = "{$option_name}_{$id}_{$lang_code}";
printf( '<div id="%s">', esc_attr( $translation_id ) );
$args['lang'] = $lang_code;
// don't use internationalized placeholders since they're not translated,
// to avoid confusion (user thinking they're all the same)
if ( $callback == 'multiple_text_input' ) {
foreach ( $fields as $key => $field_args ) {
if ( ! empty( $field_args['placeholder'] ) && isset( $field_args['i18n_placeholder'] ) ) {
$args['fields'][$key]['placeholder'] = '';
}
}
} else {
if ( !empty( $args['placeholder'] ) && isset( $args['i18n_placeholder'] ) ) {
$args['placeholder'] = '';
}
}
// specific description for internationalized fields (to compensate for missing placeholder)
if ( ! empty( $args['i18n_description'] ) ) {
$args['description'] = $args['i18n_description'];
}
if ( is_array( $callback ) ) {
call_user_func( $callback, $args );
} else {
call_user_func( array( $this, $callback ), $args );
}
echo '</div>';
}
?>
</div>
<?php
} else {
$args['lang'] = 'default';
if ( is_array( $callback ) ) {
call_user_func( $callback, $args );
} else {
call_user_func( array( $this, $callback ), $args );
}
}
}
public function get_languages () {
$multilingual = function_exists( 'icl_get_languages' );
// $multilingual = true; // for development
if ( $multilingual ) {
// use this instead of function call for development outside of WPML
// $icl_get_languages = 'a:3:{s:2:"en";a:8:{s:2:"id";s:1:"1";s:6:"active";s:1:"1";s:11:"native_name";s:7:"English";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"English";s:13:"language_code";s:2:"en";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/en.png";s:3:"url";s:23:"http://yourdomain/about";}s:2:"fr";a:8:{s:2:"id";s:1:"4";s:6:"active";s:1:"0";s:11:"native_name";s:9:"Français";s:7:"missing";s:1:"0";s:15:"translated_name";s:6:"French";s:13:"language_code";s:2:"fr";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/fr.png";s:3:"url";s:29:"http://yourdomain/fr/a-propos";}s:2:"it";a:8:{s:2:"id";s:2:"27";s:6:"active";s:1:"0";s:11:"native_name";s:8:"Italiano";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"Italian";s:13:"language_code";s:2:"it";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/it.png";s:3:"url";s:26:"http://yourdomain/it/circa";}}';
// $icl_get_languages = unserialize($icl_get_languages);
$icl_get_languages = icl_get_languages( 'skip_missing=0' );
$languages = array();
foreach ($icl_get_languages as $lang => $data) {
$languages[$data['language_code']] = $data['native_name'];
}
} else {
return false;
}
return $languages;
}
public function normalize_settings_args ( $args ) {
$args['value'] = isset( $args['value'] ) ? $args['value'] : 1;
$args['placeholder'] = isset( $args['placeholder'] ) ? $args['placeholder'] : '';
$args['store_unchecked'] = isset( $args['store_unchecked'] ) && $args['store_unchecked'] ? true : false;
// get main settings array
$option = get_option( $args['option_name'] );
if ( empty ( $args['setting_name'] ) ) {
$args['setting_name'] = "{$args['option_name']}[{$args['id']}]";
}
if ( !isset($args['lang']) && !empty($args['translatable']) ) {
$args['lang'] = 'default';
}
if ( ! array_key_exists( 'current', $args ) ) {
if (isset($args['lang'])) {
// i18n settings name
$args['setting_name'] = "{$args['setting_name']}[{$args['lang']}]";
// copy current option value if set
if ( $args['lang'] == 'default' && !empty($option[$args['id']]) && !isset( $option[$args['id']]['default'] ) ) {
// we're switching back from WPML to normal
// try english first
if ( isset( $option[$args['id']]['en'] ) ) {
$args['current'] = $option[$args['id']]['en'];
} elseif ( is_array( $option[$args['id']] ) ) {
// fallback to the first language if english not found
$first = array_shift($option[$args['id']]);
if (!empty($first)) {
$args['current'] = $first;
}
} elseif ( is_string( $option[$args['id']] ) ) {
$args['current'] = $option[$args['id']];
} else {
// nothing, really?
$args['current'] = '';
}
} else {
if ( isset( $option[$args['id']][$args['lang']] ) ) {
$args['current'] = $option[$args['id']][$args['lang']];
} elseif (isset( $option[$args['id']]['default'] )) {
$args['current'] = $option[$args['id']]['default'];
}
}
} else {
// copy current option value if set
if ( isset( $option[$args['id']] ) ) {
$args['current'] = $option[$args['id']];
}
}
}
// falback to default or empty if no value in option
if ( !isset($args['current']) ) {
$args['current'] = isset( $args['default'] ) ? $args['default'] : '';
} elseif ( empty($args['current']) && isset($args['default_if_empty']) && $args['default_if_empty'] == true ) { // force fallback if empty 'current' and 'default_if_empty' equals to true
$args['current'] = isset( $args['default'] ) ? $args['default'] : '';
}
return $args;
}
/**
* Validate options.
*
* @param array $input options to valid.
*
* @return array validated options.
*/
public function validate( $input ) {
// Create our array for storing the validated options.
$output = array();
if ( empty( $input ) || ! is_array( $input ) ) {
return $input;
}
if ( ! empty( $input['wpo_wcpdf_setting_store_empty'] ) ) { //perhaps we should use a more unique/specific name for this
foreach ( $input['wpo_wcpdf_setting_store_empty'] as $key ) {
if ( empty( $input[$key] ) ) {
$output[$key] = 0;
}
}
unset($input['wpo_wcpdf_setting_store_empty']);
}
// Loop through each of the incoming options.
foreach ( $input as $key => $value ) {
// Check to see if the current option has a value. If so, process it.
if ( isset( $input[$key] ) ) {
if ( is_array( $input[$key] ) ) {
foreach ( $input[$key] as $sub_key => $sub_value ) {
$output[$key][$sub_key] = $input[$key][$sub_key];
}
} else {
$output[$key] = $input[$key];
}
}
}
// Return the array processing any additional functions filtered by this action.
return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
}
}
endif; // class_exists

View File

@@ -0,0 +1,810 @@
<?php
namespace WPO\WC\PDF_Invoices\Settings;
use WPO\WC\PDF_Invoices\Tables\Number_Store_List_Table;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings\\Settings_Debug' ) ) :
class Settings_Debug {
protected static $_instance = null;
public $sections;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
$this->sections = array(
'settings' => __( 'Settings', 'woocommerce-pdf-invoices-packing-slips' ),
'status' => __( 'Status', 'woocommerce-pdf-invoices-packing-slips' ),
'tools' => __( 'Tools', 'woocommerce-pdf-invoices-packing-slips' ),
'numbers' => __( 'Numbers', 'woocommerce-pdf-invoices-packing-slips' ),
);
add_action( 'admin_init', array( $this, 'init_settings' ) );
add_action( 'wpo_wcpdf_settings_output_debug', array( $this, 'output' ), 10, 1 );
add_action( 'wp_ajax_wpo_wcpdf_debug_tools', array( $this, 'ajax_process_settings_debug_tools' ) );
add_action( 'wp_ajax_wpo_wcpdf_danger_zone_tools', array( $this, 'ajax_process_danger_zone_tools' ) );
}
public function output( $active_section ) {
$active_section = ! empty( $active_section ) ? $active_section : 'settings';
?>
<div class="wcpdf_debug_settings_sections">
<h2 class="nav-tab-wrapper">
<?php
foreach ( $this->sections as $section => $title ) {
$active = ( $section === $active_section ) ? 'nav-tab-active' : '';
printf( '<a href="%1$s" class="nav-tab nav-tab-%2$s %3$s">%4$s</a>', esc_url( add_query_arg( 'section', $section ) ), esc_attr( $section ), $active, esc_html( $title ) );
}
?>
</h2>
</div>
<?php
switch ( $active_section ) {
case 'settings':
$this->display_settings();
break;
case 'status':
$this->display_status();
break;
case 'tools':
$this->process_debug_tools();
$this->display_tools();
break;
case 'numbers':
$this->display_numbers();
break;
}
}
public function display_settings() {
settings_fields( 'wpo_wcpdf_settings_debug' );
do_settings_sections( 'wpo_wcpdf_settings_debug' );
submit_button();
}
public function display_status() {
include( WPO_WCPDF()->plugin_path() . '/includes/views/advanced-status.php' );
}
public function display_tools() {
include( WPO_WCPDF()->plugin_path() . '/includes/views/advanced-tools.php' );
}
public function display_numbers() {
global $wpdb;
$number_store_tables = $this->get_number_store_tables();
$invoice_number_store_doc_types = WPO_WCPDF()->settings->debug->get_additional_invoice_number_store_document_types();
$store_name = 'invoice_number';
if ( isset( $_GET['table_name'] ) ) {
$selected_table_name = esc_attr( $_GET['table_name'] );
} else {
$_GET['table_name'] = $selected_table_name = apply_filters( 'wpo_wcpdf_number_store_table_name', "{$wpdb->prefix}wcpdf_{$store_name}", $store_name, null ); // i.e. wp_wcpdf_invoice_number or wp_wcpdf_invoice_number_2021
}
if ( ! isset( $number_store_tables[ $_GET['table_name'] ] ) ) {
$_GET['table_name'] = $selected_table_name = null;
}
$document_type = WPO_WCPDF()->settings->debug->get_document_type_from_store_table_name( esc_attr( $_GET['table_name'] ) );
$list_table = new Number_Store_List_Table();
$list_table->prepare_items();
include( WPO_WCPDF()->plugin_path() . '/includes/views/advanced-numbers.php' );
}
private function get_number_store_tables() {
global $wpdb;
$tables = $wpdb->get_results( "SHOW TABLES LIKE '{$wpdb->prefix}wcpdf_%'" );
$document_titles = WPO_WCPDF()->documents->get_document_titles();
$table_names = array();
foreach ( $tables as $table ) {
foreach ( $table as $table_name ) {
if ( ! empty ( $table_name ) ) {
// strip the default prefix
$store_name = $full_store_name = substr( $table_name, strpos( $table_name, 'wcpdf_' ) + strlen( 'wcpdf_' ) );
// strip year suffix, if present
if ( is_numeric( substr( $full_store_name, -4 ) ) ) {
$store_name = trim( substr( $full_store_name, 0, -4 ), '_' );
}
if ( empty( $store_name ) || empty( $full_store_name ) ) {
continue;
}
// strip '_number' and other remaining suffixes
$suffix = substr( $full_store_name, strpos( $full_store_name, '_number' ) + strlen( '_number' ) );
$clean_suffix = ! empty( $suffix ) ? trim( str_replace( '_number', '', $suffix ), '_' ) : $suffix;
$name = substr( $store_name, 0, strpos( $store_name, '_number' ) );
$title = '';
if ( ! empty( $name ) ) {
$title = ! empty( $document_titles[ $name ] ) ? $document_titles[ $name ] : ucwords( str_replace( array( "__", "_", "-" ), ' ', $name ) );
}
if ( ! empty ( $suffix ) ) {
$title = "{$title} ({$clean_suffix})";
}
$table_names[ $table_name ] = $title;
}
}
}
ksort( $table_names );
return $table_names;
}
public function get_document_type_from_store_table_name( $table_name ) {
$document_type = '';
if ( empty( $table_name ) ) {
return $document_type;
}
// strip the default prefix
$store_name = $full_store_name = substr( $table_name, strpos( $table_name, 'wcpdf_' ) + strlen( 'wcpdf_' ) );
// strip year suffix, if present
if ( is_numeric( substr( $full_store_name, -4 ) ) ) {
$store_name = trim( substr( $full_store_name, 0, -4 ), '_' );
}
if ( ! empty( $store_name ) && ! empty( $full_store_name ) ) {
$name = substr( $store_name, 0, strpos( $store_name, '_number' ) );
$document_type = ! empty( $name ) ? str_replace( '_', '-', $name ) : '';
}
return $document_type;
}
public function get_additional_invoice_number_store_document_types() {
$additional_doc_types = array();
$documents = WPO_WCPDF()->documents->get_documents();
foreach ( $documents as $document ) {
if ( in_array( $document->get_type(), array( 'proforma', 'credit-note' ) ) && $document->is_enabled() && is_callable( array( $document, 'get_number_sequence' ) ) ) {
$number_sequence = $document->get_number_sequence( '', $document );
if ( 'invoice_number' === $number_sequence ) {
$additional_doc_types[] = $document->get_type();
}
}
}
return $additional_doc_types;
}
public function process_debug_tools() {
if ( isset( $_REQUEST['wpo_wcpdf_debug_tools_action'] ) && is_callable( array( $this, $_REQUEST['wpo_wcpdf_debug_tools_action'] ) ) ) {
if ( check_admin_referer( 'wpo_wcpdf_debug_tools_action', 'security' ) ) {
// generate_random_string, install_fonts, reschedule_yearly_reset, clear_tmp
call_user_func( array( $this, $_REQUEST['wpo_wcpdf_debug_tools_action'] ) );
}
}
}
private function generate_random_string() {
if ( ! empty( WPO_WCPDF()->main->get_random_string() ) ) {
$old_path = WPO_WCPDF()->main->get_tmp_base();
} else {
$old_path = WPO_WCPDF()->main->get_tmp_base( false );
}
WPO_WCPDF()->main->generate_random_string();
$new_path = WPO_WCPDF()->main->get_tmp_base();
WPO_WCPDF()->main->copy_directory( $old_path, $new_path );
WPO_WCPDF()->main->maybe_reinstall_fonts( true );
/* translators: directory path */
printf( '<div class="notice notice-success"><p>%s</p></div>', sprintf( esc_html__( 'Temporary folder moved to %s', 'woocommerce-pdf-invoices-packing-slips' ), '<code>'.$new_path.'</code>' ) );
}
private function install_fonts() {
WPO_WCPDF()->main->maybe_reinstall_fonts( true );
printf( '<div class="notice notice-success"><p>%s</p></div>', esc_html__( 'Fonts reinstalled!', 'woocommerce-pdf-invoices-packing-slips' ) );
}
private function reschedule_yearly_reset() {
WPO_WCPDF()->settings->schedule_yearly_reset_numbers();
printf( '<div class="notice notice-success"><p>%s</p></div>', esc_html__( 'Yearly reset numbering system rescheduled!', 'woocommerce-pdf-invoices-packing-slips' ) );
}
private function clear_tmp() {
$output = WPO_WCPDF()->main->temporary_files_cleanup( time() );
printf( '<div class="notice notice-%1$s"><p>%2$s</p></div>', key( $output ), reset( $output ) );
}
public function ajax_process_settings_debug_tools() {
check_ajax_referer( 'wpo_wcpdf_debug_nonce', 'nonce' );
$data = stripslashes_deep( $_REQUEST );
if ( empty( $data['action'] ) || 'wpo_wcpdf_debug_tools' !== $data['action'] || empty( $data['debug_tool'] ) ) {
return;
}
$debug_tool = str_replace( '-', '_', esc_attr( $data['debug_tool'] ) );
if ( is_callable( array( $this, $debug_tool ) ) ) {
// export_settings, import_settings, reset_settings
call_user_func_array( array( $this, $debug_tool ), array( $data ) );
}
wp_die();
}
private function export_settings( $data ) {
extract( $data );
if ( empty( $type ) ) {
$message = __( 'Export settings type is empty!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
$settings = [];
switch ( $type ) {
case 'general':
$settings = WPO_WCPDF()->settings->general_settings;
break;
case 'debug':
$settings = WPO_WCPDF()->settings->debug_settings;
break;
case 'ubl_taxes':
$settings = WPO_WCPDF()->settings->ubl_tax_settings;
break;
default:
$settings = apply_filters( 'wpo_wcpdf_export_settings', $settings, $type );
break;
}
// maybe it's a document type settings request
if ( empty( $settings ) ) {
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
$document_type = $document->get_type();
if (
$document_type === substr( $type, 0, strlen( $document_type ) ) ||
false !== strpos( $type, '_ubl' )
) {
$settings = get_option( "wpo_wcpdf_documents_settings_{$type}", [] );
break;
}
}
if ( empty( $settings ) ) {
$message = __( 'Exported settings data is empty!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
}
$filename = apply_filters( 'wpo_wcpdf_export_settings_filename', sprintf( "{$type}-settings-export_%s.json", date( 'Y-m-d_H-i-s' ) ), $type );
wp_send_json_success( compact( 'filename', 'settings' ) );
}
private function import_settings( $data ) {
extract( $data );
$file_data = [];
if ( ! empty( $_FILES['file']['tmp_name'] ) && ! empty( $_FILES['file']['name'] ) ) {
$json_data = file_get_contents( $_FILES['file']['tmp_name'], $_FILES['file']['name'] );
if ( false === $json_data ) {
$message = __( 'Failed to get contents from JSON file!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
} else {
$file_data = json_decode( $json_data, true );
}
} else {
$message = __( 'JSON file not found!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
if ( empty( $file_data ) || empty( $file_data['type'] ) || empty( $file_data['settings'] ) || ! is_array( $file_data['settings'] ) ) {
$message = __( 'The JSON file data is corrupted!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
$setting_types = $this->get_setting_types();
$type = esc_attr( $file_data['type'] );
$new_settings = stripslashes_deep( $file_data['settings'] );
$settings_option = '';
if ( ! in_array( $type, array_keys( $setting_types ) ) ) {
$message = __( 'The JSON file settings type is not supported on this store!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
if ( in_array( $type, array( 'general', 'debug', 'ubl_taxes' ) ) ) {
$settings_option = "wpo_wcpdf_settings_{$type}";
} else {
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
$document_type = $document->get_type();
if (
$document_type === substr( $type, 0, strlen( $document_type ) ) ||
false !== strpos( $type, '_ubl' )
) {
$settings_option = "wpo_wcpdf_documents_settings_{$type}";
break;
}
}
}
// used for extension settings
$settings_option = apply_filters( 'wpo_wcpdf_import_settings_option', $settings_option, $type, $new_settings );
if ( empty( $settings_option ) ) {
$message = __( "Couldn't determine the settings option for the import!", 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
$updated = update_option( $settings_option, $new_settings );
if ( $updated ) {
$message = sprintf(
/* translators: settings type */
__( '%s settings imported successfully!', 'woocommerce-pdf-invoices-packing-slips' ),
$setting_types[$type]
);
wcpdf_log_error( $message, 'info' );
wp_send_json_success( compact( 'type', 'message' ) );
} else {
$message = sprintf(
/* translators: settings type */
__( 'The %s settings file you are trying to import is identical to your current settings, therefore, the settings were not imported.', 'woocommerce-pdf-invoices-packing-slips' ),
$setting_types[$type]
);
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
}
private function reset_settings( $data ) {
extract( $data );
if ( empty( $type ) ) {
$message = __( 'Reset settings type is empty!', 'woocommerce-pdf-invoices-packing-slips' );
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
$settings_option = '';
switch ( $type ) {
case 'general':
$settings_option = 'wpo_wcpdf_settings_general';
break;
case 'debug':
$settings_option = 'wpo_wcpdf_settings_debug';
break;
case 'ubl_taxes':
$settings_option = 'wpo_wcpdf_settings_ubl_taxes';
break;
default:
$settings_option = apply_filters( 'wpo_wcpdf_reset_settings_option', $settings_option, $type );
break;
}
// maybe it's a document type settings request
if ( empty( $settings_option ) ) {
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
$document_type = $document->get_type();
if (
$document_type === substr( $type, 0, strlen( $document_type ) ) ||
false !== strpos( $type, '_ubl' )
) {
$settings_option = "wpo_wcpdf_documents_settings_{$type}";
break;
}
}
if ( empty( $settings_option ) ) {
$message = sprintf(
/* translators: settings type */
__( '%s settings reset not supported!', 'woocommerce-pdf-invoices-packing-slips' ),
$type
);
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
}
// settings already reset
$current_settings = get_option( $settings_option, [] );
if ( empty( $current_settings ) ) {
$message = sprintf(
/* translators: settings type */
__( '%s settings are already reset!', 'woocommerce-pdf-invoices-packing-slips' ),
$type
);
wcpdf_log_error( $message, 'info' );
wp_send_json_success( compact( 'type', 'message' ) );
}
// reset settings
$updated = update_option( $settings_option, [] );
if ( $updated ) {
$message = sprintf(
/* translators: settings type */
__( '%s settings reset successfully!', 'woocommerce-pdf-invoices-packing-slips' ),
$type
);
wcpdf_log_error( $message, 'info' );
wp_send_json_success( compact( 'type', 'message' ) );
} else {
$message = sprintf(
/* translators: settings type */
__( 'An error occurred when trying to reset the %s settings.', 'woocommerce-pdf-invoices-packing-slips' ),
$type
);
wcpdf_log_error( $message );
wp_send_json_error( compact( 'message' ) );
}
}
public function ajax_process_danger_zone_tools() {
check_ajax_referer( 'wpo_wcpdf_debug_nonce', 'nonce' );
$request = stripslashes_deep( $_REQUEST );
if ( ! isset( $request['document_type'] ) || ! isset( $request['date_from'] ) || ! isset( $request['date_to'] ) ) {
$message = __( 'One or more request parameters missing.', 'woocommerce-pdf-invoices-packing-slips' );
wp_send_json_error( compact( $message ) );
}
$from_date = date_i18n( 'Y-m-d', strtotime( $request['date_from'] ) );
$to_date = date_i18n( 'Y-m-d', strtotime( $request['date_to'] ) );
$document_type = esc_attr( $request['document_type'] );
$document_types = ! empty( $document_type ) && ( 'all' !== $document_type ) ? array( $document_type ) : array();
$document_title = ! empty( $document_type ) && ( 'all' !== $document_type ) ? ' ' . ucwords( str_replace( '-', ' ', $document_type ) ) . ' ' : ' ';
$page_count = absint( $request['page_count'] );
$document_count = absint( $request['document_count'] );
$delete_or_renumber = esc_attr( $request['delete_or_renumber'] );
$message = ( 'delete' === $delete_or_renumber ) ? $document_title . __( 'documents deleted.', 'woocommerce-pdf-invoices-packing-slips' ) : $document_title . __( 'documents renumbered.', 'woocommerce-pdf-invoices-packing-slips' );
$finished = false;
$args = array(
'return' => 'ids',
'type' => 'shop_order',
'limit' => -1,
'order' => 'ASC',
'paginate' => true,
'posts_per_page' => 50,
'page' => $page_count,
'date_created' => $from_date . '...' . $to_date,
);
$results = wc_get_orders( $args );
$order_ids = $results->orders;
if ( ! empty( $order_ids ) && ! empty( $document_type ) ) {
foreach ( $order_ids as $order_id ) {
$order = wc_get_order( $order_id );
if ( empty( $order ) ) {
continue;
}
if ( 'all' === $document_type ) {
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
$document_types[] = $document->get_type();
}
}
foreach ( $document_types as $type ) {
$document = wcpdf_get_document( $type, $order );
$return = $this->renumber_or_delete_document( $document, $delete_or_renumber );
if ( $return ) {
$document_count++;
}
}
}
$page_count++;
// no more order IDs
} else {
$finished = true;
}
$response = array(
'finished' => $finished,
'pageCount' => $page_count,
'documentCount' => $document_count,
'message' => $message,
);
wp_send_json_success( $response );
}
private function renumber_or_delete_document( $document, $delete_or_renumber ) {
$return = false;
if ( $document && $document->exists() ) {
switch ( $delete_or_renumber ) {
case 'renumber':
if ( is_callable( array( $document, 'init_number' ) ) ) {
$document->init_number();
$return = true;
} elseif ( 'packing-slip' === $document->get_type() && is_callable( array( WPO_WCPDF_Pro()->functions, 'init_packing_slip_number' ) ) ) {
WPO_WCPDF_Pro()->functions->init_packing_slip_number( $document );
$return = true;
}
if ( $return ) {
$document->save();
}
break;
case 'delete':
if ( is_callable( array( $document, 'delete' ) ) ) {
$document->delete();
$return = true;
}
break;
default:
break;
}
}
return $return;
}
public function get_setting_types() {
$setting_types = [
'general' => __( 'General', 'woocommerce-pdf-invoices-packing-slips' ),
'debug' => __( 'Debug', 'woocommerce-pdf-invoices-packing-slips' ),
'ubl_taxes' => __( 'UBL Taxes', 'woocommerce-pdf-invoices-packing-slips' ),
];
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
if ( $document->title != $document->get_title() ) {
$title = $document->title.' ('.$document->get_title().')';
} else {
$title = $document->get_title();
}
foreach ( $document->output_formats as $output_format ) {
$slug = $document->get_type();
if ( 'pdf' !== $output_format ) {
$slug .= "_{$output_format}";
}
$setting_types[$slug] = strtoupper( $output_format ) . ' ' . $title;
}
}
return apply_filters( 'wpo_wcpdf_setting_types', $setting_types );
}
public function init_settings() {
// Register settings.
$page = $option_group = $option_name = 'wpo_wcpdf_settings_debug';
$settings_fields = array(
array(
'type' => 'section',
'id' => 'debug_settings',
'title' => '',
'callback' => 'section',
),
array(
'type' => 'setting',
'id' => 'document_link_access_type',
'title' => __( 'Document link access type', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'document_link_access_type',
'default' => 'logged_in',
'options' => array(
'logged_in' => __( 'Logged in (recommended)', 'woocommerce-pdf-invoices-packing-slips' ),
'guest' => __( 'Guest', 'woocommerce-pdf-invoices-packing-slips' ),
'full' => __( 'Full', 'woocommerce-pdf-invoices-packing-slips' ),
),
)
),
array(
'type' => 'setting',
'id' => 'document_link_access_type_table',
'title' => '',
'callback' => array( $this, 'document_link_access_type_table' ),
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
),
),
array(
'type' => 'setting',
'id' => 'document_access_denied_redirect_page',
'title' => __( 'Document access denied redirect page', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'document_access_denied_redirect_page',
'default' => 'blank',
'options' => array(
'blank_page' => __( 'Blank page with message (default)', 'woocommerce-pdf-invoices-packing-slips' ),
'login_page' => __( 'Login page', 'woocommerce-pdf-invoices-packing-slips' ),
'myaccount_page' => __( 'My Account page', 'woocommerce-pdf-invoices-packing-slips' ),
'custom_page' => __( 'Custom page (enter below)', 'woocommerce-pdf-invoices-packing-slips' ),
),
'description' => __( 'Select a frontend page to be used to redirect users when the document access is denied.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'document_custom_redirect_page',
'title' => '',
'callback' => 'url_input',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'document_custom_redirect_page',
'placeholder' => esc_url_raw( wc_get_page_permalink( 'shop' ) ),
'description' => __( 'Custom external URLs not allowed.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'pretty_document_links',
'title' => __( 'Pretty document links', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'pretty_document_links',
'description' => __( 'Changes the document links to a prettier URL scheme.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'calculate_document_numbers',
'title' => __( 'Calculate document numbers (slow)', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'calculate_document_numbers',
'description' => __( "Document numbers (such as invoice numbers) are generated using AUTO_INCREMENT by default. Use this setting if your database auto increments with more than 1.", 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'enable_debug',
'title' => __( 'Enable debug output', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'enable_debug',
'description' => __( "Enable this option to output plugin errors if you're getting a blank page or other PDF generation issues", 'woocommerce-pdf-invoices-packing-slips' ) . '<br>' .
__( '<b>Caution!</b> This setting may reveal errors (from other plugins) in other places on your site too, therefor this is not recommended to leave it enabled on live sites.', 'woocommerce-pdf-invoices-packing-slips' ) . ' ' .
__( 'You can also add <code>&debug=true</code> to the URL to apply this on a per-order basis.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'enable_cleanup',
'title' => __( 'Enable automatic cleanup', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox_text_input',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'enable_cleanup',
/* translators: number of days */
'text_input_wrap' => __( "every %s days", 'woocommerce-pdf-invoices-packing-slips' ),
'text_input_size' => 4,
'text_input_id' => 'cleanup_days',
'text_input_default' => 7,
'description' => __( "Automatically clean up PDF files stored in the temporary folder (used for email attachments)", 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'html_output',
'title' => __( 'Output to HTML', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'html_output',
'description' => __( 'Send the template output as HTML to the browser instead of creating a PDF.', 'woocommerce-pdf-invoices-packing-slips' ) . ' ' .
__( 'You can also add <code>&output=html</code> to the URL to apply this on a per-order basis.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'log_to_order_notes',
'title' => __( 'Log to order notes', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'log_to_order_notes',
'description' => __( 'Log PDF document creation and mark/unmark as printed to order notes.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'disable_preview',
'title' => __( 'Disable document preview', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'disable_preview',
'description' => __( 'Disables the document preview on the plugin settings pages.', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'enable_danger_zone_tools',
'title' => __( 'Enable danger zone tools', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'debug_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'enable_danger_zone_tools',
'description' => __( 'Enables the danger zone tools. The actions performed by these tools are irreversible!', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
);
// allow plugins to alter settings fields
$settings_fields = apply_filters( 'wpo_wcpdf_settings_fields_debug', $settings_fields, $page, $option_group, $option_name );
WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
return;
}
public function document_link_access_type_table() {
?>
<table id="document-link-access-type">
<tr>
<td class="option"><strong><?php _e( 'Logged in', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></td>
<td><?php _e( "Document can be accessed by logged in users only.", 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
</tr>
<tr>
<td class="option"><strong><?php _e( 'Guest', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></td>
<td><?php _e( 'Document can be accessed by logged in and guest users.', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
</tr>
<tr>
<td class="option"><strong><?php _e( 'Full', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></td>
<td><?php _e( 'Document can be accessed by everyone with the link.', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
</tr>
</table>
<?php
}
}
endif; // class_exists

View File

@@ -0,0 +1,107 @@
<?php
namespace WPO\WC\PDF_Invoices\Settings;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings\\Settings_Documents' ) ) :
class Settings_Documents {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
add_action( 'admin_init', array( $this, 'init_settings' ) );
add_action( 'wpo_wcpdf_settings_output_documents', array( $this, 'output' ), 10, 1 );
}
public function init_settings() {
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
foreach ( $documents as $document ) {
if ( is_callable( array( $document, 'init_settings' ) ) ) {
$document->init_settings();
}
}
}
public function output( $section ) {
$section = ! empty( $section ) ? $section : 'invoice';
$documents = WPO_WCPDF()->documents->get_documents( 'all' );
$output_format = 'pdf';
$section_document = null;
if ( isset( $_REQUEST['output_format'] ) && 'ubl' === $_REQUEST['output_format'] ) {
$output_format = 'ubl';
}
foreach ( $documents as $document ) {
if ( $document->get_type() == $section ) {
$section_document = $document;
break;
}
}
if ( empty( $section_document ) ) {
return;
}
?>
<div class="wcpdf_document_settings_sections">
<?php echo '<h2>'.esc_html( $section_document->get_title() ).'<span class="arrow-down">&#9660;</span></h2>'; ?>
<ul>
<?php
foreach ( $documents as $document ) {
if( $document->get_type() != $section ) {
$title = strip_tags( $document->get_title() );
if ( empty( trim( $title ) ) ) {
$title = '['.__( 'untitled', 'woocommerce-pdf-invoices-packing-slips' ).']';
}
$active = $document->get_type() == $section ? 'active' : '';
printf( '<li class="%2$s"><a href="%1$s" class="%2$s">%3$s</a></li>', esc_url( add_query_arg( 'section', $document->get_type() ) ), esc_attr( $active ), esc_html( $title ) );
}
}
?>
</ul>
</div>
<div class="wcpdf_document_settings_document_output_formats">
<?php
if ( ! empty( $section_document->output_formats ) ) {
?>
<h2 class="nav-tab-wrapper">
<?php
foreach ( $section_document->output_formats as $document_output_format ) {
$active = ( $output_format == $document_output_format ) || ( 'pdf' !== $output_format && ! in_array( $output_format, $section_document->output_formats ) ) ? 'nav-tab-active' : '';
$tab_title = strtoupper( esc_html( $document_output_format ) );
if ( 'ubl' === $document_output_format ) {
$tab_title .= ' <sup class="wcpdf_beta">beta</sup>';
}
printf( '<a href="%1$s" class="nav-tab nav-tab-%2$s %3$s">%4$s</a>', esc_url( add_query_arg( 'output_format', $document_output_format ) ), esc_attr( $document_output_format ), $active, $tab_title );
}
?>
</h2>
<?php
}
?>
</div>
<?php
$output_format_compatible = false;
if ( 'pdf' !== $output_format && in_array( $output_format, $section_document->output_formats ) ) {
$output_format_compatible = true;
}
$option_name = ( 'pdf' === $output_format || ! $output_format_compatible ) ? "wpo_wcpdf_documents_settings_{$section}" : "wpo_wcpdf_documents_settings_{$section}_{$output_format}";
settings_fields( $option_name );
do_settings_sections( $option_name );
submit_button();
}
}
endif; // class_exists

View File

@@ -0,0 +1,387 @@
<?php
namespace WPO\WC\PDF_Invoices\Settings;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings\\Settings_General' ) ) :
class Settings_General {
protected $option_name = 'wpo_wcpdf_settings_general';
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
add_action( 'admin_init', array( $this, 'init_settings' ) );
add_action( 'wpo_wcpdf_settings_output_general', array( $this, 'output' ), 10, 1 );
add_action( 'wpo_wcpdf_before_settings', array( $this, 'attachment_settings_hint' ), 10, 2 );
}
public function output( $section ) {
settings_fields( $this->option_name );
do_settings_sections( $this->option_name );
submit_button();
}
public function init_settings() {
$page = $option_group = $option_name = $this->option_name;
$template_base_path = ( defined( 'WC_TEMPLATE_PATH' ) ? WC_TEMPLATE_PATH : $GLOBALS['woocommerce']->template_url );
$theme_template_path = get_stylesheet_directory() . '/' . $template_base_path;
$wp_content_dir = defined( 'WP_CONTENT_DIR' ) && ! empty( WP_CONTENT_DIR ) ? str_replace( ABSPATH, '', WP_CONTENT_DIR ) : '';
$theme_template_path = substr( $theme_template_path, strpos( $theme_template_path, $wp_content_dir ) ) . 'pdf/yourtemplate';
$plugin_template_path = "{$wp_content_dir}/plugins/woocommerce-pdf-invoices-packing-slips/templates/Simple";
$settings_fields = array(
array(
'type' => 'section',
'id' => 'general_settings',
'title' => __( 'General settings', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'section',
),
array(
'type' => 'setting',
'id' => 'download_display',
'title' => __( 'How do you want to view the PDF?', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'download_display',
'options' => array(
'download' => __( 'Download the PDF' , 'woocommerce-pdf-invoices-packing-slips' ),
'display' => __( 'Open the PDF in a new browser tab/window' , 'woocommerce-pdf-invoices-packing-slips' ),
),
)
),
array(
'type' => 'setting',
'id' => 'template_path',
'title' => __( 'Choose a template', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'template_path',
'options_callback' => array( $this, 'get_installed_templates_list' ),
/* translators: 1,2. template paths */
'description' => sprintf( __( 'Want to use your own template? Copy all the files from %1$s to your (child) theme in %2$s to customize them' , 'woocommerce-pdf-invoices-packing-slips' ), '<code>'.$plugin_template_path.'</code>', '<code>'.$theme_template_path.'</code>' ),
)
),
array(
'type' => 'setting',
'id' => 'paper_size',
'title' => __( 'Paper size', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'select',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'paper_size',
'options' => apply_filters( 'wpo_wcpdf_template_settings_paper_size', array(
'a4' => __( 'A4' , 'woocommerce-pdf-invoices-packing-slips' ),
'letter' => __( 'Letter' , 'woocommerce-pdf-invoices-packing-slips' ),
) ),
)
),
array(
'type' => 'setting',
'id' => 'test_mode',
'title' => __( 'Test mode', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'test_mode',
'description' => __( 'With test mode enabled, any document generated will always use the latest settings, rather than using the settings as configured at the time the document was first created.' , 'woocommerce-pdf-invoices-packing-slips' ) . '<br>'. __( '<strong>Note:</strong> invoice numbers and dates are not affected by this setting and will still be generated.' , 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'currency_font',
'title' => __( 'Extended currency symbol support', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'currency_font',
'description' => __( 'Enable this if your currency symbol is not displaying properly' , 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'font_subsetting',
'title' => __( 'Enable font subsetting', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'checkbox',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'font_subsetting',
'description' => __( "Font subsetting can reduce file size by only including the characters that are used in the PDF, but limits the ability to edit PDF files later. Recommended if you're using an Asian font." , 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'header_logo',
'title' => __( 'Shop header/logo', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'media_upload',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'header_logo',
'uploader_title' => __( 'Select or upload your invoice header/logo', 'woocommerce-pdf-invoices-packing-slips' ),
'uploader_button_text' => __( 'Set image', 'woocommerce-pdf-invoices-packing-slips' ),
'remove_button_text' => __( 'Remove image', 'woocommerce-pdf-invoices-packing-slips' ),
//'description' => __( '...', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'header_logo_height',
'title' => __( 'Logo height', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'text_input',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'header_logo_height',
'size' => '5',
'placeholder' => '3cm',
'description' => __( 'Enter the total height of the logo in mm, cm or in and use a dot for decimals.<br/>For example: 1.15in or 40mm', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'shop_name',
'title' => __( 'Shop Name', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'text_input',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'shop_name',
'translatable' => true,
)
),
array(
'type' => 'setting',
'id' => 'vat_number',
'title' => __( 'Shop VAT Number', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'text_input',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'vat_number',
'translatable' => true,
)
),
array(
'type' => 'setting',
'id' => 'coc_number',
'title' => __( 'Shop Chamber of Commerce Number', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'text_input',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'coc_number',
'translatable' => true,
)
),
array(
'type' => 'setting',
'id' => 'shop_address',
'title' => __( 'Shop Address', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'textarea',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'shop_address',
'width' => '72',
'height' => '8',
'translatable' => true,
//'description' => __( '...', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'setting',
'id' => 'footer',
'title' => __( 'Footer: terms & conditions, policies, etc.', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'textarea',
'section' => 'general_settings',
'args' => array(
'option_name' => $option_name,
'id' => 'footer',
'width' => '72',
'height' => '4',
'translatable' => true,
//'description' => __( '...', 'woocommerce-pdf-invoices-packing-slips' ),
)
),
array(
'type' => 'section',
'id' => 'extra_template_fields',
'title' => __( 'Extra template fields', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'custom_fields_section',
),
array(
'type' => 'setting',
'id' => 'extra_1',
'title' => __( 'Extra field 1', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'textarea',
'section' => 'extra_template_fields',
'args' => array(
'option_name' => $option_name,
'id' => 'extra_1',
'width' => '72',
'height' => '8',
'description' => __( 'This is footer column 1 in the <i>Modern (Premium)</i> template', 'woocommerce-pdf-invoices-packing-slips' ),
'translatable' => true,
)
),
array(
'type' => 'setting',
'id' => 'extra_2',
'title' => __( 'Extra field 2', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'textarea',
'section' => 'extra_template_fields',
'args' => array(
'option_name' => $option_name,
'id' => 'extra_2',
'width' => '72',
'height' => '8',
'description' => __( 'This is footer column 2 in the <i>Modern (Premium)</i> template', 'woocommerce-pdf-invoices-packing-slips' ),
'translatable' => true,
)
),
array(
'type' => 'setting',
'id' => 'extra_3',
'title' => __( 'Extra field 3', 'woocommerce-pdf-invoices-packing-slips' ),
'callback' => 'textarea',
'section' => 'extra_template_fields',
'args' => array(
'option_name' => $option_name,
'id' => 'extra_3',
'width' => '72',
'height' => '8',
'description' => __( 'This is footer column 3 in the <i>Modern (Premium)</i> template', 'woocommerce-pdf-invoices-packing-slips' ),
'translatable' => true,
)
),
);
// allow plugins to alter settings fields
$settings_fields = apply_filters( 'wpo_wcpdf_settings_fields_general', $settings_fields, $page, $option_group, $option_name );
WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
return;
}
public function attachment_settings_hint( $active_tab, $active_section ) {
// save or check option to hide attachments settings hint
if ( isset( $_REQUEST['wpo_wcpdf_hide_attachments_hint'] ) && isset( $_REQUEST['_wpnonce'] ) ) {
// validate nonce
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'hide_attachments_hint_nonce' ) ) {
wcpdf_log_error( 'You do not have sufficient permissions to perform this action: wpo_wcpdf_hide_attachments_hint' );
$hide_hint = false;
} else {
update_option( 'wpo_wcpdf_hide_attachments_hint', true );
$hide_hint = true;
}
} else {
$hide_hint = get_option( 'wpo_wcpdf_hide_attachments_hint' );
}
if ( $active_tab == 'general' && ! $hide_hint ) {
$documents = WPO_WCPDF()->documents->get_documents();
foreach ( $documents as $document ) {
if ( $document->get_type() == 'invoice' ) {
$invoice_email_ids = $document->get_attach_to_email_ids();
if ( empty( $invoice_email_ids ) ) {
include_once( WPO_WCPDF()->plugin_path() . '/includes/views/attachment-settings-hint.php' );
}
}
}
}
}
public function get_installed_templates_list() {
$installed_templates = WPO_WCPDF()->settings->get_installed_templates();
$template_list = array();
foreach ( $installed_templates as $path => $template_id ) {
$template_name = basename( $template_id );
$group = dirname( $template_id );
switch ( $group ) {
case 'default':
case 'premium_plugin':
// no suffix
break;
case 'theme':
default:
$template_name = sprintf( '%s (%s)', $template_name, __( 'Custom', 'woocommerce-pdf-invoices-packing-slips' ) );
break;
}
$template_list[$template_id] = $template_name;
}
return $template_list;
}
/**
* List templates in plugin folder, theme folder & child theme folder
* @return array template path => template name
*/
public function find_templates() {
$installed_templates = array();
// get base paths
$template_base_path = ( function_exists( 'WC' ) && is_callable( array( WC(), 'template_path' ) ) ) ? WC()->template_path() : apply_filters( 'woocommerce_template_path', 'woocommerce/' );
$template_base_path = untrailingslashit( $template_base_path );
$template_paths = array (
// note the order: child-theme before theme, so that array_unique filters out parent doubles
'default' => WPO_WCPDF()->plugin_path() . '/templates/',
'child-theme' => get_stylesheet_directory() . "/{$template_base_path}/pdf/",
'theme' => get_template_directory() . "/{$template_base_path}/pdf/",
);
$template_paths = apply_filters( 'wpo_wcpdf_template_paths', $template_paths );
if ( defined( 'WP_CONTENT_DIR' ) && ! empty( WP_CONTENT_DIR ) && false !== strpos( WP_CONTENT_DIR, ABSPATH ) ) {
$forwardslash_basepath = str_replace( '\\', '/', ABSPATH );
} else {
$forwardslash_basepath = str_replace( '\\', '/', WP_CONTENT_DIR );
}
foreach ( $template_paths as $template_source => $template_path ) {
$dirs = (array) glob( $template_path . '*' , GLOB_ONLYDIR );
foreach ( $dirs as $dir ) {
if ( empty( $dir ) ) {
continue;
}
// we're stripping abspath to make the plugin settings more portable
$forwardslash_dir = str_replace( '\\', '/', $dir );
$installed_templates[ str_replace( $forwardslash_basepath, '', $forwardslash_dir ) ] = basename( $dir );
}
}
// remove parent doubles
$installed_templates = array_unique( $installed_templates );
if ( empty( $installed_templates ) ) {
// fallback to Simple template for servers with glob() disabled
$simple_template_path = str_replace( ABSPATH, '', $template_paths['default'] . 'Simple' );
$installed_templates[$simple_template_path] = 'Simple';
}
return apply_filters( 'wpo_wcpdf_templates', $installed_templates );
}
}
endif; // class_exists

View File

@@ -0,0 +1,163 @@
<?php
namespace WPO\WC\PDF_Invoices\Settings;
use WPO\WC\UBL\Settings\TaxesSettings as UBL_Tax_Settings;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings\\Settings_UBL' ) ) :
class Settings_UBL {
public $sections;
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
function __construct() {
$this->sections = [
'taxes' => __( 'Taxes classification', 'woocommerce-pdf-invoices-packing-slips' ),
];
add_action( 'admin_init', array( $this, 'init_tax_settings' ) );
add_action( 'wpo_wcpdf_settings_output_ubl', array( $this, 'output' ), 10, 1 );
add_action( 'woocommerce_order_after_calculate_totals', array( $this, 'save_taxes_on_order_totals' ), 10, 2 );
add_action( 'woocommerce_checkout_order_processed', array( $this, 'save_taxes_on_checkout' ), 10, 3 );
// VAT number or COC number is empty
add_action( 'admin_notices', array( $this, 'vat_coc_required_for_ubl_invoice') );
}
public function output( $active_section ) {
$active_section = ! empty( $active_section ) ? $active_section : 'taxes';
?>
<div class="wcpdf_ubl_settings_sections">
<?php if ( count( $this->sections ) > 1 ) : ?>
<h2 class="nav-tab-wrapper">
<?php
foreach ( $this->sections as $section => $title ) {
$active = ( $section == $active_section ) ? 'nav-tab-active' : '';
printf( '<a href="%1$s" class="nav-tab nav-tab-%2$s %3$s">%4$s</a>', esc_url( add_query_arg( 'section', $section ) ), esc_attr( $section ), $active, esc_html( $title ) );
}
?>
</h2>
<?php else : ?>
<h3><?php echo $this->sections[ $active_section ]; ?></h3>
<?php endif; ?>
</div>
<?php
switch ( $active_section ) {
default:
case 'taxes':
$setting = new UBL_Tax_Settings();
$setting->output();
break;
}
}
public function init_tax_settings() {
$page = $option_group = $option_name = 'wpo_wcpdf_settings_ubl_taxes';
$settings_fields = array(
array(
'type' => 'section',
'id' => 'taxes',
'title' => '',
'callback' => 'section',
),
);
$settings_fields = apply_filters( 'wpo_wcpdf_settings_fields_ubl_taxes', $settings_fields, $page, $option_group, $option_name );
WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
}
public function save_taxes_on_order_totals( $and_taxes, $order ) {
// it seems $and taxes is mostly false, meaning taxes are calculated separately,
// but we still update just in case anything changed
if ( ! empty( $order ) ) {
$this->save_order_taxes( $order );
}
}
public function save_taxes_on_checkout( $order_id, $posted_data, $order ) {
if ( empty( $order ) && ! empty( $order_id ) ) {
$order = wc_get_order( $order_id );
}
if ( $order ) {
$this->save_order_taxes( $order );
}
}
public function save_order_taxes( $order ) {
foreach ( $order->get_taxes() as $item_id => $tax_item ) {
if ( is_a( $tax_item, '\WC_Order_Item_Tax' ) && is_callable( array( $tax_item, 'get_rate_id' ) ) ) {
// get tax rate id from item
$tax_rate_id = $tax_item->get_rate_id();
// read tax rate data from db
if ( class_exists( '\WC_TAX' ) && is_callable( array( '\WC_TAX', '_get_tax_rate' ) ) ) {
$tax_rate = \WC_Tax::_get_tax_rate( $tax_rate_id, OBJECT );
if ( ! empty( $tax_rate ) && is_numeric( $tax_rate->tax_rate ) ) {
// store percentage in tax item meta
wc_update_order_item_meta( $item_id, '_wcpdf_rate_percentage', $tax_rate->tax_rate );
$ubl_tax_settings = get_option( 'wpo_wcpdf_settings_ubl_taxes' );
$category = isset( $ubl_tax_settings['rate'][$tax_rate->tax_rate_id]['category'] ) ? $ubl_tax_settings['rate'][$tax_rate->tax_rate_id]['category'] : '';
$scheme = isset( $ubl_tax_settings['rate'][$tax_rate->tax_rate_id]['scheme'] ) ? $ubl_tax_settings['rate'][$tax_rate->tax_rate_id]['scheme'] : '';
$tax_rate_class = $tax_rate->tax_rate_class;
if ( empty( $tax_rate_class ) ) {
$tax_rate_class = 'standard';
}
if ( empty( $category ) ) {
$category = isset( $ubl_tax_settings['class'][$tax_rate_class]['category'] ) ? $ubl_tax_settings['class'][$tax_rate_class]['category'] : '';
}
if ( empty( $scheme ) ) {
$scheme = isset( $ubl_tax_settings['class'][$tax_rate_class]['scheme'] ) ? $ubl_tax_settings['class'][$tax_rate_class]['scheme'] : '';
}
if ( ! empty( $category ) ) {
wc_update_order_item_meta( $item_id, '_wcpdf_ubl_tax_category', $category );
}
if ( ! empty( $scheme ) ) {
wc_update_order_item_meta( $item_id, '_wcpdf_ubl_tax_scheme', $scheme );
}
}
}
}
}
}
public function vat_coc_required_for_ubl_invoice() {
$invoice_ubl_settings = WPO_WCPDF()->settings->get_document_settings( 'invoice', 'ubl' );
if ( isset( $invoice_ubl_settings['enabled'] ) && ( ! isset( WPO_WCPDF()->settings->general_settings['vat_number'] ) || ! isset( WPO_WCPDF()->settings->general_settings['coc_number'] ) ) ) {
$message = sprintf(
/* translators: 1. General Settings, 2. UBL Settings */
__( 'You\'ve enabled UBL output for a document, but some essential details are missing. Please ensure you\'ve added your VAT and CoC numbers in the %1$s. Also, specify your tax rates in the %2$s.', 'woocommerce-pdf-invoices-packing-slips' ),
'<a href="' . esc_url( admin_url( 'admin.php?page=wpo_wcpdf_options_page' ) ) . '">' . __( 'General settings', 'woocommerce-pdf-invoices-packing-slips' ) . '</a>',
'<a href="' . esc_url( admin_url( 'admin.php?page=wpo_wcpdf_options_page&tab=ubl' ) ) . '">' . __( 'UBL settings', 'woocommerce-pdf-invoices-packing-slips' ) . '</a>'
);
echo '<div class="notice notice-warning"><p>' . $message . '</p></div>';
}
}
}
endif; // class_exists

View File

@@ -0,0 +1,245 @@
<?php
namespace WPO\WC\PDF_Invoices\Settings;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings\\Settings_Upgrade' ) ) :
class Settings_Upgrade {
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct() {
add_action( 'wpo_wcpdf_after_settings_page', array( $this, 'extension_overview' ), 10, 2 );
}
public function extension_overview( $tab, $section ) {
if ( 'upgrade' === $tab ) {
$features = array(
array(
'label' => __( 'Proforma Invoice, Credit Note & Receipt', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Update your workflow and handle refunds. Both Proforma & Credit Note documents can either follow the main invoice numbering or have their own separate number sequence.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Attach to email', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Also attach the Packing Slip, Proforma Invoice and Credit Note to any of the outgoing emails.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Cloud storage upload', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Automatically upload your documents via FTP/SFTP or to Dropbox.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Bulk export', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Easily export documents for a specific date range.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Multilingual support', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Handle document translations with WPML, Polylang, Weglot, TranslatePress or GTranslate.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Attach static files', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Add up to three static files to your emails.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Custom document titles and filenames', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Customize document titles and filenames right in the plugin settings.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Custom address format', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Customize the address format of the billing and shipping addresses.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'Order notification email', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => sprintf(
'%s <a href="%s" target="_blank">%s</a>',
__( 'Send a notification email to user specified addresses.', 'woocommerce-pdf-invoices-packing-slips' ),
'https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/configuring-the-order-notification-email/',
__( 'Learn more', 'woocommerce-pdf-invoices-packing-slips' )
),
'extensions' => array( 'pro', 'bundle' ),
),
array(
'label' => __( 'PDF Customizer', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => sprintf(
'%s <a href="%s" target="_blank">%s</a>',
__( 'Fully customize the product table and totals table on your documents.', 'woocommerce-pdf-invoices-packing-slips' ),
'https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/using-the-customizer/',
__( 'Learn more', 'woocommerce-pdf-invoices-packing-slips' )
),
'extensions' => array( 'templates', 'bundle' ),
),
array(
'label' => __( 'Add custom data to your documents', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => sprintf(
'%s <a href="%s" target="_blank">%s</a>',
__( 'Display all sorts of data and apply conditional logic using Custom Blocks.', 'woocommerce-pdf-invoices-packing-slips' ),
'https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/using-custom-blocks/',
__( 'Learn more', 'woocommerce-pdf-invoices-packing-slips' )
),
'extensions' => array( 'templates', 'bundle' ),
),
array(
'label' => __( 'Additional PDF templates', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Make use of our Business or Modern template designs.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'templates', 'bundle' ),
),
array(
'label' => __( 'Add styling', 'woocommerce-pdf-invoices-packing-slips' ),
'description' => __( 'Easily change the look and feel of your documents by adding some custom CSS.', 'woocommerce-pdf-invoices-packing-slips' ),
'extensions' => array( 'templates', 'bundle' ),
),
);
$extension_license_infos = $this->get_extension_license_infos();
include( WPO_WCPDF()->plugin_path() . '/includes/views/upgrade-table.php' );
}
}
/**
* Check if a PDF extension is enabled
*
* @param string $extension can be 'pro' or 'templates'
* @return boolean
*/
public function extension_is_enabled( $extension ) {
$is_enabled = false;
if ( ! empty( $extension ) || ! in_array( $extension, [ 'pro', 'templates' ] ) ) {
$extension_main_function = "WPO_WCPDF_".ucfirst( $extension );
if ( function_exists( $extension_main_function ) ) {
$is_enabled = true;
}
}
return $is_enabled;
}
/**
* Get PDF extensions license info
*
* @return array
*/
public function get_extension_license_infos() {
$extensions = [ 'pro', 'templates' ];
$license_info = [];
$bundle_upgrade_link = '';
$license_status = 'inactive';
foreach ( $extensions as $extension ) {
$license_info[$extension] = [];
$args = [];
$request = null;
$license_key = '';
$sidekick = false;
$updater = null;
if ( $this->extension_is_enabled( $extension ) ) {
$extension_main_function = "WPO_WCPDF_".ucfirst( $extension );
$updater = $extension_main_function()->updater;
if ( $extension == 'templates' && version_compare( $extension_main_function()->version, '2.20.0', '<=' ) ) { // 'updater' property had 'private' visibility
continue;
}
if ( is_null( $updater ) ) {
continue;
}
// built-in updater
if ( is_callable( [ $updater, 'get_license_key' ] ) ) {
$license_key = $updater->get_license_key();
// sidekick (legacy)
} elseif ( property_exists( $updater, 'license_key' ) ) {
$license_slug = "wpo_wcpdf_{$extension}_license";
$wpo_license_keys = get_option( 'wpocore_settings', array() );
$license_key = isset( $wpo_license_keys[$license_slug] ) ? $wpo_license_keys[$license_slug] : $license_key;
$sidekick = true;
}
if ( ! empty( $license_key ) ) {
$args['edd_action'] = 'check_license';
$args['license_key'] = trim( $license_key );
// legacy
if ( $sidekick ) {
if ( ! class_exists( 'WPO_Update_Helper' ) ) {
include_once( $extension_main_function()->plugin_path() . '/updater/update-helper.php' );
}
$item_name = 'PDF Invoices & Packing Slips for WooCommerce - ';
$file = $extension_main_function()->plugin_path();
$version = $extension_main_function()->version;
$author = 'WP Overnight';
switch ( $extension ) {
case 'pro':
$item_name = "{$item_name}Professional";
break;
case 'templates':
$item_name = "{$item_name}Premium Templates";
break;
}
$updater = new \WPO_Update_Helper( $item_name, $file, $license_slug, $version, $author );
}
} else {
continue;
}
if ( $updater && is_callable( [ $updater, 'remote_license_actions' ] ) && ! empty( $args ) ) {
$request = $updater->remote_license_actions( $args );
if ( is_object( $request ) && isset( $request->license ) ) {
$license_info[$extension]['status'] = $license_status = $request->license;
if ( empty( $bundle_upgrade_link ) && ! empty( $request->bundle_upgrade ) && is_string( $request->bundle_upgrade ) ) {
$bundle_upgrade_link = $request->bundle_upgrade; // https://github.com/wpovernight/woocommerce-pdf-invoices-packing-slips/pull/503#issue-1678203436
}
}
}
}
}
$extensions[] = 'bundle';
foreach ( $extensions as $extension ) {
if ( ! empty( $bundle_upgrade_link ) && $license_status == 'valid' ) {
$license_info[$extension]['url'] = $bundle_upgrade_link;
} else {
switch ( $extension ) {
case 'pro':
$license_info[$extension]['url'] = 'https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/';
break;
case 'templates':
$license_info[$extension]['url'] = 'https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/';
break;
case 'bundle':
$license_info[$extension]['url'] = 'https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/';
break;
}
}
}
return $license_info;
}
}
endif; // class_exists

View File

@@ -0,0 +1,300 @@
<?php
namespace WPO\WC\PDF_Invoices\Tables;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
// load WP_List_Table if not loaded
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Tables\\Number_Store_List_Table' ) ) :
class Number_Store_List_Table extends \WP_List_Table {
/**
* Number of items per page
*
* @var int
* @since 2.0
*/
public $per_page = 50;
/**
* The arguments for the data set
*
* @var array
* @since 2.0
*/
public $args = array();
/**
* Get things started
*
* @since 2.0
* @see WP_List_Table::__construct()
*/
public function __construct() {
parent::__construct( array(
'singular' => 'number',
'plural' => 'numbers',
'ajax' => false
) );
$this->process_bulk_action();
}
/**
* This function renders most of the columns in the list table.
*
* @since 2.0
*
* @param object $item Contains all the data of the numbers
* @param string $column_name The name of the column
*
* @return string Column Name
*/
public function column_default( $item, $column_name ) {
switch ( $column_name ) {
case 'number' :
$value = $item->id;
break;
case 'type' :
$value = isset( $item->document_title ) ? esc_attr( $item->document_title ) : '-';
break;
case 'calculated_number' :
$value = isset( $item->calculated_number ) ? $item->calculated_number : '-';
break;
case 'date' :
$value = $item->date;
break;
case 'order' :
if ( ! empty( $item->order_id ) ) {
$order = $this->get_base_order( wc_get_order( $item->order_id ) );
$order_number = is_callable( array( $order, 'get_order_number' ) ) ? $order->get_order_number() : $item->order_id;
$order_id = is_callable( array( $order, 'get_id' ) ) ? $order->get_id() : $item->order_id;
$url = sprintf( 'post.php?post=%s&action=edit', $order_id );
$value = sprintf( '<a href="%s">#%s</a>', $url, $order_number );
if ( absint( $order_id ) !== absint( $item->order_id ) ) {
$value .= sprintf( ' (%s #%s)', __( 'Refund:', 'woocommerce-pdf-invoices-packing-slips' ), $item->order_id );
}
} else {
$value = '-';
}
break;
case 'order_status' :
$order = $this->get_base_order( wc_get_order( $item->order_id ) );
if ( ! empty( $order ) ) {
$value = sprintf(
'<mark class="order-status %s"><span>%s</span></mark>',
esc_attr( sanitize_html_class( 'status-' . $order->get_status() ) ),
esc_html( wc_get_order_status_name( $order->get_status() ) )
);
} else {
$value = '<strong>' . __( 'Unknown', 'woocommerce-pdf-invoices-packing-slips' ) . '</strong>';
}
break;
default:
$value = isset( $item->$column_name ) ? $item->$column_name : null;
break;
}
if ( empty( $value ) ) {
$value = '-';
}
return apply_filters( 'wpo_wcpdf_number_tools_column_content_' . $column_name, $value, $item );
}
/**
* Retrieve the table columns
*
* @since 2.0
* @return array $columns Array of all the list table columns
*/
public function get_columns() {
$columns = array(
'number' => __( 'Number', 'woocommerce-pdf-invoices-packing-slips' ),
'type' => __( 'Type', 'woocommerce-pdf-invoices-packing-slips' ),
'calculated_number' => __( 'Calculated', 'woocommerce-pdf-invoices-packing-slips' ),
'date' => __( 'Date', 'woocommerce-pdf-invoices-packing-slips' ),
'order' => __( 'Order', 'woocommerce-pdf-invoices-packing-slips' ),
'order_status' => __( 'Order Status', 'woocommerce-pdf-invoices-packing-slips' ),
);
$table_name = isset( $_GET['table_name'] ) ? sanitize_text_field( $_GET['table_name'] ) : null;
$document_type = WPO_WCPDF()->settings->debug->get_document_type_from_store_table_name( $table_name );
if ( empty( $document_type ) || 'invoice' !== $document_type ) {
unset( $columns['type'] );
}
if ( ! isset( WPO_WCPDF()->settings->debug_settings['calculate_document_numbers'] ) ) {
unset( $columns['calculated_number'] );
}
return apply_filters( 'wpo_wcpdf_number_tools_columns', $columns );
}
/**
* Get the sortable columns
*
* @since 2.0
* @return array Array of all the sortable columns
*/
public function get_sortable_columns() {
return array(
'number' => array( 'id', true ),
);
}
/**
* Retrieve the bulk actions
*
* @access public
* @since 2.0
* @return array Array of the bulk actions
*/
public function get_bulk_actions() {
return array();
}
/**
* Retrieve the current page number
*
* @since 2.0
* @return int Current page number
*/
public function get_paged() {
return isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
}
/**
* Retrieves the search query string
*
* @since 2.0
* @return mixed string If search is present, false otherwise
*/
public function get_search() {
return ! empty( $_GET['s'] ) ? urldecode( trim( $_GET['s'] ) ) : false;
}
/**
* Build all the number data
*
* @since 2.0
* @global object $wpdb Used to query the database using the WordPress
* Database API
* @return array $numbers All the data for number list table
*/
public function get_numbers() {
global $wpdb;
$results = array();
$paged = $this->get_paged();
$offset = $this->per_page * ( $paged - 1 );
$search = $this->get_search();
$table_name = isset( $_GET['table_name'] ) ? sanitize_text_field( $_GET['table_name'] ) : null;
$order = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : 'DESC';
$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( $_GET['orderby'] ) : 'id';
$document_type = WPO_WCPDF()->settings->debug->get_document_type_from_store_table_name( $table_name );
$invoice_number_store_doc_types = WPO_WCPDF()->settings->debug->get_additional_invoice_number_store_document_types();
if ( 'invoice' !== $document_type && in_array( $document_type, $invoice_number_store_doc_types ) ) {
return array(); // using `invoice_number`
}
if ( ! empty( $table_name ) ) {
if ( $search ) {
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE `id` LIKE '$search' OR `order_id` LIKE '$search' ORDER BY $orderby $order LIMIT %d OFFSET %d", $this->per_page, $offset ) );
} else {
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name ORDER BY $orderby $order LIMIT %d OFFSET %d", $this->per_page, $offset ) );
}
} else {
$results = array();
}
// add document title or 'Deleted'
if ( ! empty( $results ) && ! empty( $document_type ) ) {
foreach ( $results as $key => $result ) {
$result = (array) $result;
$document_types = array( $document_type );
$order_id = isset( $result['order_id'] ) ? absint( $result['order_id'] ) : 0;
if ( 0 === $order_id ) {
continue;
}
if ( 'invoice' === $document_type && ! empty( $invoice_number_store_doc_types ) ) {
$document_types = array_merge( $document_types, $invoice_number_store_doc_types );
}
foreach ( $document_types as $doc_type ) {
$document = wcpdf_get_document( $doc_type, wc_get_order( $order_id ) );
if ( $document && is_callable( array( $document, 'get_number' ) ) ) {
$number_obj = $document->get_number();
if ( ! empty( $number_obj ) && ! empty( $number_obj->number ) ) {
if ( isset( $result['id'] ) && absint( $result['id'] ) === absint( $number_obj->number ) ) {
$results[ $key ]->document_title = $document->get_title();
}
}
}
}
}
}
return $results;
}
/**
* Setup the final data for the table
*
* @since 2.0
* @uses self::get_columns()
* @uses WP_List_Table::get_sortable_columns()
* @uses self::get_pagenum()
* @return void
*/
public function prepare_items() {
$this->_column_headers = array(
$this->get_columns(),
array(),
$this->get_sortable_columns()
);
$this->items = $this->get_numbers();
$total_items = count( $this->items );
$per_page = apply_filters( 'wpo_wcpdf_number_store_list_table_per_page', $this->per_page );
// Setup pagination
$this->set_pagination_args( array(
'total_pages' => ceil( $total_items / $per_page ),
'total_items' => $total_items,
'per_page' => $per_page
) );
}
/**
* Get the parent order for refunds
*
* @since 2.4
* @param $order WC_Order
* @return $order WC_Order
*/
public function get_base_order( $order ) {
if ( is_callable( array( $order, 'get_type' ) ) && 'shop_order_refund' === $order->get_type() ) {
return wc_get_order( $order->get_parent_id() );
} else {
return $order;
}
}
}
endif; // class_exists

View File

@@ -0,0 +1,47 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wcpdf_document_settings_sections wcpdf_advanced_numbers_choose_table">
<?php
$choose_table_title = isset( $number_store_tables[ $selected_table_name ] ) ? esc_attr( $number_store_tables[ $selected_table_name ] ) : __( 'Choose a number store', 'woocommerce-pdf-invoices-packing-slips' );
echo '<h2>' . esc_html( $choose_table_title ) . '<span class="arrow-down">&#9660;</span></h2>';
?>
<ul>
<?php
foreach ( $number_store_tables as $table_name => $title ) {
if ( isset( $_GET['table_name'] ) && $table_name !== $_GET['table_name'] ) {
if ( empty( trim( $title ) ) ) {
$title = '[' . __( 'untitled', 'woocommerce-pdf-invoices-packing-slips' ) . ']';
}
printf( '<li><a href="%1$s">%2$s</a></li>', esc_url( add_query_arg( 'table_name', esc_attr( $table_name ) ) ), esc_html( $title ) );
}
}
?>
</ul>
<?php if ( ! empty( $document_type ) && 'invoice' !== $document_type && in_array( $document_type, $invoice_number_store_doc_types ) ) : ?>
<div class="notice notice-warning inline">
<p><?php _e( 'This document is currently using the main invoice number sequence.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<?php elseif ( ! empty( $selected_table_name ) && ! empty( $number_store_tables[ $selected_table_name ] ) ) : ?>
<p>
<?php
printf(
/* translators: chose table title */
__( 'Below is a list of all the document numbers generated since the last reset (which happens when you set the <strong>next %s number</strong> value in the settings).', 'woocommerce-pdf-invoices-packing-slips' ),
$choose_table_title
);
?>
</p>
<p><?php _e( 'Numbers may have been assigned to orders before this.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<div class="number-search" style="text-align:right;">
<input type="search" id="number_search_input" name="number_search_input" value="<?php echo isset( $_REQUEST['s'] ) ? esc_attr( $_REQUEST['s'] ) : ''; ?>">
<a href="#" class="button button-primary number-search-button"><?php _e( 'Search number', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
<?php $disabled = ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) ? '' : 'disabled'; ?>
<a href="<?php echo esc_url( remove_query_arg( 's' ) ); ?>" class="button button-secondary" <?php echo $disabled; ?>><?php _e( 'Reset', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</div>
<?php $list_table->display(); ?>
<?php else : ?>
<div class="notice notice-info inline">
<p><?php _e( 'Please select a number store!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,344 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
$memory_limit = function_exists( 'wc_let_to_num' ) ? wc_let_to_num( WP_MEMORY_LIMIT ) : woocommerce_let_to_num( WP_MEMORY_LIMIT );
$php_mem_limit = function_exists( 'memory_get_usage' ) ? @ini_get( 'memory_limit' ) : '-';
$server_configs = apply_filters( 'wpo_wcpdf_server_configs' , array(
'PHP version' => array(
'required' => __( '7.2+ (7.4 or higher recommended)', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => PHP_VERSION,
'result' => version_compare( PHP_VERSION, '7.2', '>' ),
),
'DOMDocument extension' => array(
'required' => true,
'value' => phpversion( 'DOM' ),
'result' => class_exists( 'DOMDocument' ),
),
'MBString extension' => array(
'required' => true,
'value' => phpversion( 'mbstring' ),
'result' => function_exists( 'mb_send_mail' ),
'fallback' => __( 'Recommended, will use fallback functions', 'woocommerce-pdf-invoices-packing-slips' ),
),
'GD' => array(
'required' => true,
'value' => phpversion( 'gd' ),
'result' => function_exists( 'imagecreate' ),
'fallback' => __( 'Required if you have images in your documents', 'woocommerce-pdf-invoices-packing-slips' ),
),
'WebP Support' => array(
'required' => __( 'Required when using .webp images', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => null,
'result' => function_exists( 'imagecreatefromwebp' ),
'fallback' => __( 'Required if you have .webp images in your documents', 'woocommerce-pdf-invoices-packing-slips' ),
),
// "PCRE" => array(
// "required" => true,
// "value" => phpversion("pcre"),
// "result" => function_exists("preg_match") && @preg_match("/./u", "a"),
// "failure" => "PCRE is required with Unicode support (the \"u\" modifier)",
// ),
'Zlib' => array(
'required' => __( 'To compress PDF documents', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => phpversion( 'zlib' ),
'result' => function_exists( 'gzcompress' ),
'fallback' => __( 'Recommended to compress PDF documents', 'woocommerce-pdf-invoices-packing-slips' ),
),
'opcache' => array(
'required' => __( 'For better performances', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => null,
'result' => false,
'fallback' => __( 'Recommended for better performances', 'woocommerce-pdf-invoices-packing-slips' ),
),
'GMagick or IMagick' => array(
'required' => __( 'Better with transparent PNG images', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => null,
'result' => extension_loaded( 'gmagick' ) || extension_loaded( 'imagick' ),
'fallback' => __( 'Recommended for better performances', 'woocommerce-pdf-invoices-packing-slips' ),
),
'glob()' => array(
'required' => __( 'Required to detect custom templates and to clear the temp folder periodically', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => null,
'result' => function_exists( 'glob' ),
'fallback' => __( 'Check PHP disable_functions', 'woocommerce-pdf-invoices-packing-slips' ),
),
'WP Memory Limit' => array(
/* translators: <a> tags */
'required' => sprintf( __( 'Recommended: 128MB (more for plugin-heavy setups<br/>See: %1$sIncreasing the WordPress Memory Limit%2$s', 'woocommerce-pdf-invoices-packing-slips' ), '<a href="https://docs.woocommerce.com/document/increasing-the-wordpress-memory-limit/" target="_blank">', '</a>' ),
'value' => sprintf( 'WordPress: %s, PHP: %s', WP_MEMORY_LIMIT, $php_mem_limit ),
'result' => $memory_limit > 67108864,
),
'allow_url_fopen' => array (
'required' => __( 'Allow remote stylesheets and images', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => null,
'result' => ini_get( 'allow_url_fopen' ),
'fallback' => __( 'allow_url_fopen disabled', 'woocommerce-pdf-invoices-packing-slips' ),
),
'base64_decode' => array (
'required' => __( 'To compress and decompress font data', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => null,
'result' => function_exists( 'base64_decode' ),
'fallback' => __( 'base64_decode disabled', 'woocommerce-pdf-invoices-packing-slips' ),
),
) );
if ( ( $xc = extension_loaded( 'xcache' ) ) || ( $apc = extension_loaded( 'apc' ) ) || ( $zop = extension_loaded( 'Zend OPcache' ) ) || ( $op = extension_loaded( 'opcache' ) ) ) {
$server_configs['opcache']['result'] = true;
$server_configs['opcache']['value'] = (
$xc ? 'XCache '.phpversion( 'xcache' ) : (
$apc ? 'APC '.phpversion( 'apc' ) : (
$zop ? 'Zend OPCache '.phpversion( 'Zend OPcache' ) : 'PHP OPCache '.phpversion( 'opcache' )
)
)
);
}
if ( ( $gm = extension_loaded( 'gmagick' ) ) || ( $im = extension_loaded( 'imagick' ) ) ) {
$server_configs['GMagick or IMagick']['value'] = ( $im ? 'IMagick '.phpversion( 'imagick' ) : 'GMagick '.phpversion( 'gmagick' ) );
}
if ( ! $server_configs['PHP version']['result'] ) {
/* translators: <a> tags */
$server_configs['PHP version']['required'] .= '<br/>' . sprintf( __( 'Download %1$sthis addon%2$s to enable backwards compatibility.', 'woocommerce-pdf-invoices-packing-slips' ), '<a href="https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/backwards-compatibility-with-php-5-6/" target="_blank">', '</a>' );
}
?>
<table class="widefat system-status-table" cellspacing="1px" cellpadding="4px" style="width:100%;">
<thead>
<tr>
<td colspan="3"><strong><?php esc_html_e( 'System Configuration', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></td>
</tr>
</thead>
<tbody>
<tr>
<th align="left">&nbsp;</th>
<th align="left"><?php esc_html_e( 'Required', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
<th align="left"><?php esc_html_e( 'Present', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
</tr>
<?php
foreach ( $server_configs as $label => $server_config ) :
if ( $server_config['result'] ) {
$background = '#68de7c'; // green
$color = 'black';
} elseif ( isset( $server_config['fallback'] ) ) {
$background = '#f2d675'; // yellow
$color = 'black';
} else {
$background = '#ffabaf'; // red
$color = 'black';
}
?>
<tr>
<td class="title"><?php echo esc_html( $label ); ?></td>
<td><?php echo wp_kses_post( $server_config['required'] === true ? esc_html__( 'Yes', 'woocommerce-pdf-invoices-packing-slips' ) : $server_config['required'] ); ?></td>
<td style="background-color:<?php echo esc_attr( $background ); ?>; color:<?php echo esc_attr( $color ); ?>">
<?php
echo wp_kses_post( $server_config['value'] );
if ( $server_config['result'] && ! $server_config['value'] ) echo esc_html__( 'Yes', 'woocommerce-pdf-invoices-packing-slips' );
if ( ! $server_config['result'] ) {
if ( isset( $server_config['fallback'] ) ) {
printf( '<div>%s. %s</div>', esc_html__( 'No', 'woocommerce-pdf-invoices-packing-slips' ), esc_html( $server_config['fallback'] ) );
}
if ( isset( $server_config['failure'] ) ) {
printf( '<div>%s</div>', wp_kses_post( $server_config['failure'] ) );
}
}
?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<table class="widefat system-status-table" cellspacing="1px" cellpadding="4px" style="width:100%;">
<thead>
<tr>
<td colspan="3"><strong><?php esc_html_e( 'Documents status', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></td>
</tr>
</thead>
<tbody>
<tr>
<th align="left">&nbsp;</th>
<th align="left"><?php esc_html_e( 'Enabled', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
<th align="left"><?php esc_html_e( 'Yearly reset', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
</tr>
<?php
foreach ( WPO_WCPDF()->documents->get_documents( 'all' ) as $document ) :
$is_reset_enabled = isset( $document->settings['reset_number_yearly'] ) ? true : false;
$is_enabled = $document->is_enabled() ? true : false;
?>
<tr>
<td class="title"><?php echo esc_html( $document->get_title() ); ?></td>
<td style="<?= $is_enabled ? 'background-color:#68de7c; color:black;' : 'background-color:#ffabaf; color:black;' ?>"><?php echo wp_kses_post( $is_enabled === true ? esc_html__( 'Yes', 'woocommerce-pdf-invoices-packing-slips' ) : esc_html__( 'No', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></td>
<td style="<?= $is_reset_enabled ? 'background-color:#68de7c; color:black;' : 'background-color:#ffabaf; color:black;' ?>"><?php echo wp_kses_post( $is_reset_enabled === true ? esc_html__( 'Yes', 'woocommerce-pdf-invoices-packing-slips' ) : esc_html__( 'No', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></td>
</tr>
</tbody>
<?php endforeach; ?>
<?php
if ( WPO_WCPDF()->settings->maybe_schedule_yearly_reset_numbers() ) :
if ( function_exists( 'as_get_scheduled_actions' ) ) {
$scheduled_actions = as_get_scheduled_actions( array(
'hook' => 'wpo_wcpdf_schedule_yearly_reset_numbers',
'status' => \ActionScheduler_Store::STATUS_PENDING,
) );
$yearly_reset = array(
'required' => __( 'Required to reset documents numeration', 'woocommerce-pdf-invoices-packing-slips' ),
'fallback' => __( 'Yearly reset action not found', 'woocommerce-pdf-invoices-packing-slips' ),
);
if ( ! empty( $scheduled_actions ) ) {
$total_actions = count( $scheduled_actions );
if ( $total_actions === 1 ) {
$action = reset( $scheduled_actions );
$action_date = is_callable( array( $action->get_schedule(), 'get_date' ) ) ? $action->get_schedule()->get_date() : $action->get_schedule()->get_next( as_get_datetime_object() );
/* translators: action date */
$yearly_reset['value'] = sprintf(
__( 'Scheduled to: %s' ), date( wcpdf_date_format( null, 'yearly_reset_schedule' ),
$action_date->getTimeStamp() )
);
$yearly_reset['result'] = true;
} else {
/* translators: total actions */
$yearly_reset['value'] = sprintf(
/* translators: total scheduled actions */
__( 'Only 1 scheduled action should exist, but %s were found', 'woocommerce-pdf-invoices-packing-slips' ),
$total_actions
);
$yearly_reset['result'] = false;
}
} else {
$yearly_reset['value'] = sprintf(
/* translators: <a></a> tags */
__( 'Scheduled action not found. Please reschedule it %shere%s.', 'woocommerce-pdf-invoices-packing-slips' ),
'<a href="' . esc_url( add_query_arg( 'section', 'tools' ) ) . '" style="color:black; text-decoration:underline;">',
'</a>'
);
$yearly_reset['result'] = false;
}
}
$label = __( 'Yearly reset', 'woocommerce-pdf-invoices-packing-slips' );
if ( $yearly_reset['result'] ) {
$background = '#68de7c'; // green
$color = 'black';
} else {
$background = '#ffabaf'; // red
$color = 'black';
}
?>
<tfoot>
<tr>
<td class="title"><strong><?php echo esc_html( $label ); ?></strong></td>
<td colspan="2" style="background-color:<?php echo esc_attr( $background ); ?>; color:<?php echo esc_attr( $color ); ?>">
<?php
echo wp_kses_post( $yearly_reset['value'] );
if ( $yearly_reset['result'] && ! $yearly_reset['value'] ) {
echo esc_html__( 'Yes', 'woocommerce-pdf-invoices-packing-slips' );
}
?>
</td>
</tr>
</tfoot>
<?php endif; ?>
</table>
<?php
$status = array(
'ok' => __( 'Writable', 'woocommerce-pdf-invoices-packing-slips' ),
'failed' => __( 'Not writable', 'woocommerce-pdf-invoices-packing-slips' ),
);
$permissions = apply_filters( 'wpo_wcpdf_plugin_directories', array(
'WCPDF_TEMP_DIR' => array (
'description' => __( 'Central temporary plugin folder', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => WPO_WCPDF()->main->get_tmp_path(),
'status' => is_writable( WPO_WCPDF()->main->get_tmp_path() ) ? 'ok' : 'failed',
'status_message' => is_writable( WPO_WCPDF()->main->get_tmp_path() ) ? $status['ok'] : $status['failed'],
),
'WCPDF_ATTACHMENT_DIR' => array (
'description' => __( 'Temporary attachments folder', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => trailingslashit( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ),
'status' => is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? 'ok' : 'failed',
'status_message' => is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? $status['ok'] : $status['failed'],
),
'DOMPDF_TEMP_DIR' => array (
'description' => __( 'Temporary DOMPDF folder', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => trailingslashit(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )),
'status' => is_writable(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )) ? 'ok' : 'failed',
'status_message' => is_writable(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )) ? $status['ok'] : $status['failed'],
),
'DOMPDF_FONT_DIR' => array (
'description' => __( 'DOMPDF fonts folder (needs to be writable for custom/remote fonts)', 'woocommerce-pdf-invoices-packing-slips' ),
'value' => trailingslashit(WPO_WCPDF()->main->get_tmp_path( 'fonts' )),
'status' => is_writable(WPO_WCPDF()->main->get_tmp_path( 'fonts' )) ? 'ok' : 'failed',
'status_message' => is_writable(WPO_WCPDF()->main->get_tmp_path( 'fonts' )) ? $status['ok'] : $status['failed'],
),
), $status );
$upload_dir = wp_upload_dir();
$upload_base = trailingslashit( $upload_dir['basedir'] );
?>
<table class="widefat system-status-table" cellspacing="1px" cellpadding="4px" style="width:100%;">
<thead>
<tr>
<td colspan="3"><strong><?php esc_html_e( 'Write Permissions', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></td>
</tr>
</thead>
<tbody>
<tr>
<th align="left">&nbsp;</th>
<th align="left"><?php esc_html_e( 'Path', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
<th align="left"><?php esc_html_e( 'Status', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
</tr>
<?php
foreach ( $permissions as $permission ) {
if ( $permission['status'] == 'ok' ) {
$background = '#68de7c'; // green
$color = 'black';
} else {
$background = '#ffabaf'; // red
$color = 'black';
}
?>
<tr>
<td><?php echo wp_kses_post( $permission['description'] ); ?></td>
<td><?php echo ! empty( $permission['value'] ) ? str_replace( array('/','\\' ), array('/<wbr>','\\<wbr>' ), wp_kses_post( $permission['value'] ) ) : ''; ?></td>
<td style="background-color:<?php echo esc_attr( $background ); ?>; color:<?php echo esc_attr( $color ); ?>"><?php echo wp_kses_post( $permission['status_message'] ); ?></td>
</tr>
<?php } ?>
</tbody>
<tfoot>
<tr>
<td colspan="3">
<?php
/* translators: 1,2. directory paths, 3. UPLOADS, 4. wpo_wcpdf_tmp_path, 5. attachments, 6. dompdf, 7. fonts */
printf( esc_attr__( 'The central temp folder is %1$s. By default, this folder is created in the WordPress uploads folder (%2$s), which can be defined by setting %3$s in wp-config.php. Alternatively, you can control the specific folder for PDF invoices by using the %4$s filter. Make sure this folder is writable and that the subfolders %5$s, %6$s and %7$s are present (these will be created by the plugin if the central temp folder is writable).', 'woocommerce-pdf-invoices-packing-slips' ),
'<code>'.WPO_WCPDF()->main->get_tmp_path().'</code>',
'<code>'.$upload_base.'</code>',
'<code>UPLOADS</code>',
'<code>wpo_wcpdf_tmp_path</code>',
'<code>attachments</code>',
'<code>dompdf</code>',
'<code>fonts</code>'
);
?>
</td>
</tr>
<tr>
<td colspan="3">
<?php
/* translators: directory path */
printf( esc_attr__('If the temporary folders were not automatically created by the plugin, verify that all the font files (from %s) are copied to the fonts folder. Normally, this is fully automated, but if your server has strict security settings, this automated copying may have been prohibited. In that case, you also need to make sure these folders get synchronized on plugin updates!', 'woocommerce-pdf-invoices-packing-slips' ),
'<code>'.WPO_WCPDF()->plugin_path() . "/vendor/dompdf/dompdf/lib/fonts/".'</code>'
);
?>
</td>
</tr>
</tfoot>
</table>

View File

@@ -0,0 +1,215 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div id="debug-tools">
<div class="wrapper">
<?php do_action( 'wpo_wcpdf_before_debug_tools', $this ); ?>
<!-- generate_random_string -->
<div class="tool">
<h4><?php _e( 'Generate random temporary directory', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'For security reasons, it is preferable to use a random name for the temporary directory.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form method="post">
<?php wp_nonce_field( 'wpo_wcpdf_debug_tools_action', 'security' ); ?>
<input type="hidden" name="wpo_wcpdf_debug_tools_action" value="generate_random_string">
<input type="submit" name="submit" id="submit" class="button" value="<?php esc_attr_e( 'Generate temporary directory', 'woocommerce-pdf-invoices-packing-slips' ); ?>">
</form>
</div>
<!-- /generate_random_string -->
<!-- install_fonts -->
<div class="tool">
<h4><?php _e( 'Reinstall plugin fonts', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'If you are experiencing issues with rendering fonts there might have been an issue during installation or upgrade.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form method="post">
<?php wp_nonce_field( 'wpo_wcpdf_debug_tools_action', 'security' ); ?>
<input type="hidden" name="wpo_wcpdf_debug_tools_action" value="install_fonts">
<input type="submit" name="submit" id="submit" class="button" value="<?php esc_attr_e( 'Reinstall fonts', 'woocommerce-pdf-invoices-packing-slips' ); ?>">
</form>
</div>
<!-- /install_fonts -->
<!-- reschedule_yearly_reset -->
<?php if ( ! WPO_WCPDF()->settings->yearly_reset_action_is_scheduled() ) : ?>
<div class="tool">
<h4><?php _e( 'Reschedule the yearly reset of the numbering system', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( "You seem to have the yearly reset enabled for one of your documents but the action that performs this isn't scheduled yet.", 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form method="post">
<?php wp_nonce_field( 'wpo_wcpdf_debug_tools_action', 'security' ); ?>
<input type="hidden" name="wpo_wcpdf_debug_tools_action" value="reschedule_yearly_reset">
<input type="submit" name="submit" id="submit" class="button" value="<?php esc_attr_e( 'Reschedule yearly reset', 'woocommerce-pdf-invoices-packing-slips' ); ?>">
</form>
</div>
<?php endif; ?>
<!-- /reschedule_yearly_reset -->
<!-- clear_tmp -->
<div class="tool">
<h4><?php _e( 'Remove temporary files', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'Clean up the PDF files stored in the temporary folder (used for email attachments).', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form method="post">
<?php wp_nonce_field( 'wpo_wcpdf_debug_tools_action', 'security' ); ?>
<input type="hidden" name="wpo_wcpdf_debug_tools_action" value="clear_tmp">
<input type="submit" name="submit" id="submit" class="button" value="<?php esc_attr_e( 'Remove temporary files', 'woocommerce-pdf-invoices-packing-slips' ); ?>">
</form>
</div>
<!-- /clear_tmp -->
<!-- run_wizard -->
<div class="tool">
<h4><?php _e( 'Run the Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'Set up your basic invoice workflow via our Wizard.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wpo-wcpdf-setup' ) ); ?>" class="button"><?php esc_html_e( 'Run the Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</div>
<!-- /run_wizard -->
<!-- export_settings -->
<div class="tool">
<h4><?php _e( 'Export Settings', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'Download plugin settings in JSON format to easily export your current setup.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form class="wpo_wcpdf_debug_tools_form" method="post">
<input type="hidden" name="debug_tool" value="export-settings">
<fieldset>
<select name="type" required>
<?php
foreach ( $this->get_setting_types() as $type => $name ) {
?>
<option value="<?php echo $type; ?>"><?php echo $name; ?></option>
<?php
}
?>
</select>
<a href="" class="button button-secondary submit"><?php _e( 'Export', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</fieldset>
<fieldset>
<div class="notice inline" style="display:none;"><p></p></div>
</fieldset>
</form>
</div>
<!-- /export_settings -->
<!-- import_settings -->
<div class="tool">
<h4><?php _e( 'Import Settings', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'Import plugin settings in JSON format.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form class="wpo_wcpdf_debug_tools_form" method="post" enctype="multipart/form-data">
<input type="hidden" name="debug_tool" value="import-settings">
<fieldset>
<input type="file" name="file" accept="application/json" required>
<a href="" class="button button-secondary submit"><?php _e( 'Import', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</fieldset>
<fieldset>
<div class="notice inline" style="display:none;"><p></p></div>
</fieldset>
</form>
</div>
<!-- /import_settings -->
<!-- reset_settings -->
<div class="tool">
<h4><?php _e( 'Reset Settings', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'This will clear all your selected settings data. Please do a backup first using the export tool above.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<form class="wpo_wcpdf_debug_tools_form" method="post">
<input type="hidden" name="debug_tool" value="reset-settings">
<fieldset>
<select name="type" required>
<?php
foreach ( $this->get_setting_types() as $type => $name ) {
?>
<option value="<?php echo $type; ?>"><?php echo $name; ?></option>
<?php
}
?>
</select>
<a href="" class="button button-secondary submit"><?php _e( 'Reset', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</fieldset>
<fieldset>
<div class="notice inline" style="display:none;"><p></p></div>
</fieldset>
</form>
</div>
<!-- /reset_settings -->
<?php do_action( 'wpo_wcpdf_after_debug_tools', $this ); ?>
</div>
<!-- danger_zone (admin access only) -->
<?php if ( current_user_can( 'administrator' ) && isset( WPO_WCPDF()->settings->debug_settings['enable_danger_zone_tools'] ) ) : ?>
<?php $documents = WPO_WCPDF()->documents->get_documents( 'all' ); ?>
<div id="danger_zone" class="wrapper">
<div class="tool">
<div class="notice notice-warning inline">
<p><?php _e( '<strong>DANGER ZONE:</strong> Create a backup before using these tools, the actions they perform are irreversible!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
</div>
<!-- renumber_documents -->
<div class="tool">
<h4><?php _e( 'Renumber existing documents', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'This tool will renumber existing documents within the selected order date range, while keeping the assigned document date.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<p>
<?php
printf(
/* translators: step-by-step instructions */
__( 'Set the <strong>next document number</strong> setting %s to the number you want to use for the first document. ', 'woocommerce-pdf-invoices-packing-slips' ),
'<code>WooCommerce > PDF Invoices > Documents > Select document</code>'
);
?>
</p>
<table>
<tr>
<td><?php _e( 'Document type:', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
<td>
<select id="renumber-document-type" name="renumber-document-type">
<option value=""><?php _e( 'Select', 'woocommerce-pdf-invoices-packing-slips' ); ?>...</option>
<?php foreach ( $documents as $document ) : ?>
<option value="<?php echo $document->get_type(); ?>"><?php echo $document->get_title(); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<td><?php _e( 'From:', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
<td><input type="text" id="renumber-date-from" name="renumber-date-from" value="<?php echo date( 'Y-m-d' ); ?>" size="10"><span class="add-info"><?php _e( '(as: yyyy-mm-dd)', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></td>
</tr>
<tr>
<td><?php _e( 'To:', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
<td><input type="text" id="renumber-date-to" name="renumber-date-to" value="<?php echo date( 'Y-m-d' ); ?>" size="10"><span class="add-info"><?php _e( '(as: yyyy-mm-dd)', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<button class="button button-large number-tools-btn" id="renumber-documents-btn"><?php _e( 'Renumber documents', 'woocommerce-pdf-invoices-packing-slips' ); ?></button>
<div class="spinner renumber-spinner"></div>
</td>
</tr>
</table>
</div>
<!-- /renumber_documents -->
<!-- delete_documents -->
<div class="tool">
<h4><?php _e( 'Delete existing documents', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<p><?php _e( 'This tool will delete existing documents within the selected order date range.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<table>
<tr>
<td><?php _e( 'Document type:', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
<td>
<select id="delete-document-type" name="delete-document-type">
<option value=""><?php _e( 'Select', 'woocommerce-pdf-invoices-packing-slips' ); ?>...</option>
<?php foreach ( $documents as $document ) : ?>
<option value="<?php echo $document->get_type(); ?>"><?php echo $document->get_title(); ?></option>
<?php endforeach; ?>
<option value="all"><?php _e( 'All', 'woocommerce-pdf-invoices-packing-slips' ); ?></option>
</select>
</td>
</tr>
<tr>
<td><?php _e( 'From:', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
<td><input type="text" id="delete-date-from" name="delete-date-from" value="<?php echo date( 'Y-m-d' ); ?>" size="10"><span class="add-info"><?php _e( '(as: yyyy-mm-dd)', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></td>
</tr>
<tr>
<td><?php _e( 'To:', 'woocommerce-pdf-invoices-packing-slips' ); ?></td>
<td><input type="text" id="delete-date-to" name="delete-date-to" value="<?php echo date( 'Y-m-d' ); ?>" size="10"><span class="add-info"><?php _e( '(as: yyyy-mm-dd)', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<button class="button button-large number-tools-btn" id="delete-documents-btn"><?php _e( 'Delete documents', 'woocommerce-pdf-invoices-packing-slips' ); ?></button>
<div class="spinner delete-spinner"></div>
</td>
</tr>
</table>
</div>
<!-- /delete_documents -->
</div>
<?php endif; ?>
<!-- /danger_zone (admin access only) -->
</div>

View File

@@ -0,0 +1,14 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<?php
$invoice_settings_url = esc_url( add_query_arg( array(
'tab' => 'documents',
'section' => 'invoice',
) ) );
?>
<div class="wcpdf-attachment-settings-hint notice inline">
<p>
<?php /* translators: <a> tags */ ?>
<?php printf( wp_kses_post( __( 'It looks like you haven\'t setup any email attachments yet, check the settings under <b>%1$sDocuments > Invoice%2$s</b>', 'woocommerce-pdf-invoices-packing-slips' ) ), '<a href="'.$invoice_settings_url.'">', '</a>' ); ?>
<?php printf( '<a href="%s" style="display:block; margin-top:10px;">%s</a>', esc_url( wp_nonce_url( add_query_arg( 'wpo_wcpdf_hide_attachments_hint', 'true' ), 'hide_attachments_hint_nonce' ) ), esc_html__( 'Hide this message', 'woocommerce-pdf-invoices-packing-slips' ) ); ?>
</p>
</div>

View File

@@ -0,0 +1,124 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wcpdf-extensions-ad">
<?php $no_pro = ! class_exists( 'WooCommerce_PDF_IPS_Pro' ) && ! class_exists( 'WPO_WCPDF_Templates' ); ?>
<img src="<?php echo esc_url( WPO_WCPDF()->plugin_url() . '/assets/images/wpo-helper.png' ); ?>" class="wpo-helper">
<h3><?php esc_html_e( 'Check out these premium extensions!', 'woocommerce-pdf-invoices-packing-slips' ); ?></h3>
<i>(<?php esc_html_e( 'click items to read more', 'woocommerce-pdf-invoices-packing-slips' ); ?>)</i>
<ul class="wcpdf-extensions">
<?php if ( $no_pro ): ?>
<!-- No Pro extensions: Ad for PDF bundle -->
<li>
<?php esc_html_e( 'Premium PDF Invoice bundle: Everything you need for a perfect invoicing system', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<div class="more" style="display:none;">
<h4><?php esc_html_e( 'Supercharge PDF Invoices & Packing Slips for WooCommerce with the all our premium extensions:', 'woocommerce-pdf-invoices-packing-slips' ); ?></h4>
<?php esc_html_e( 'Professional features:', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<ul>
<li><?php echo wp_kses_post( __( 'Email/print/download <b>PDF Credit Notes & Proforma invoices</b>', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Send out a separate <b>notification email</b> with (or without) PDF invoices/packing slips, for example to a drop-shipper or a supplier.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Attach <b>up to 3 static files</b> (for example a terms & conditions document) to the WooCommerce emails of your choice.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Use <b>separate numbering systems</b> and/or format for proforma invoices and credit notes or utilize the main invoice numbering system', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( '<b>Customize</b> the <b>shipping & billing address</b> format to include additional custom fields, font sizes etc. without the need to create a custom template.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Use the plugin in multilingual <b>WPML</b> setups', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
</ul>
<?php esc_html_e( 'Advanced, customizable templates', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<ul>
<li><?php echo wp_kses_post( __( 'Completely customize the invoice contents (prices, taxes, thumbnails) to your needs with a drag & drop customizer', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Two extra stylish premade templates (Modern & Business)', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
</ul>
<?php esc_html_e( 'Upload automatically to dropbox', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<ul>
<li><?php echo wp_kses_post( __( 'This extension conveniently uploads all the invoices (and other pdf documents from the professional extension) that are emailed to your customers to Dropbox. The best way to keep your invoice administration up to date!', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
</ul>
<br>
<a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/" target="_blank"><?php esc_html_e( "Get PDF Invoices & Packing Slips for WooCommerce Bundle", 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</div>
</li>
<?php endif; ?>
<?php
// NO BUNDLE: separate ads
if ( ! class_exists( 'WooCommerce_PDF_IPS_Pro' ) && ! $no_pro ) {
?>
<li>
<?php esc_html_e( 'Go Pro: Proforma invoices, credit notes (=refunds) & more!', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<div class="more" style="display:none;">
<?php esc_html_e( 'Supercharge PDF Invoices & Packing Slips for WooCommerce with the following features:', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<ul>
<li><?php echo wp_kses_post( __( 'Email/print/download <b>PDF Credit Notes & Proforma invoices</b>', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Send out a separate <b>notification email</b> with (or without) PDF invoices/packing slips, for example to a drop-shipper or a supplier.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Attach <b>up to 3 static files</b> (for example a terms & conditions document) to the WooCommerce emails of your choice.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Use <b>separate numbering systems</b> and/or format for proforma invoices and credit notes or utilize the main invoice numbering system', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( '<b>Customize</b> the <b>shipping & billing address</b> format to include additional custom fields, font sizes etc. without the need to create a custom template.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Use the plugin in multilingual <b>WPML</b> setups', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Upload automatically to dropbox', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
</ul>
<a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/" target="_blank"><?php esc_html_e( "Get PDF Invoices & Packing Slips for WooCommerce Professional!", 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</li>
<?php } ?>
<?php
if ( ! class_exists( 'WPO_WC_Smart_Reminder_Emails' ) ) {
?>
<li>
<?php esc_html_e( 'Automatically send payment reminders to your customers', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<div class="more" style="display:none;">
<?php esc_html_e( 'WooCommerce Smart Reminder emails', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<ul>
<li><?php echo wp_kses_post( __( '<b>Completely automatic</b> scheduled emails', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( '<b>Rich text editor</b> for the email text, including placeholders for data from the order (name, order total, etc)', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Configure the exact requirements for sending an email (time after order, order status, payment method)', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( 'Fully <b>WPML Compatible</b> emails will be automatically sent in the order language.', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><?php echo wp_kses_post( __( '<b>Super versatile!</b> Can be used for any kind of reminder email (review reminders, repeat purchases)', 'woocommerce-pdf-invoices-packing-slips' ) ); ?></li>
<li><b><?php esc_html_e( 'Integrates seamlessly with the PDF Invoices & Packing Slips plugin', 'woocommerce-pdf-invoices-packing-slips' ); ?></b></li>
</ul>
<a href="https://wpovernight.com/downloads/woocommerce-reminder-emails-payment-reminders/" target="_blank"><?php esc_html_e( "Get WooCommerce Smart Reminder Emails", 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</div>
</li>
<?php } ?>
<?php
if ( ! class_exists( 'WooCommerce_Ext_PrintOrders' ) ) {
?>
<li>
<?php esc_html_e( 'Automatically send new orders or packing slips to your printer, as soon as the customer orders!', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<div class="more" style="display:none;">
<table>
<tr>
<td><img src="<?php echo esc_url( WPO_WCPDF()->plugin_url() . '/assets/images/cloud-print.png' ); ?>" class="cloud-logo"></td>
<td>
<?php esc_html_e( 'Check out the WooCommerce Automatic Order Printing extension from our partners at Simba Hosting', 'woocommerce-pdf-invoices-packing-slips' ); ?><br/>
<a href="https://www.simbahosting.co.uk/s3/product/woocommerce-printnode-automatic-order-printing/?affiliates=2" target="_blank"><?php esc_html_e( "WooCommerce Automatic Order Printing", 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
</td>
</tr>
</table>
</div>
</li>
<?php } ?>
<?php
if ( ! class_exists( 'WooCommerce_PDF_IPS_Templates' ) && ! class_exists( 'WPO_WCPDF_Templates' ) && ! $no_pro ) {
$template_link = '<a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/" target="_blank">wpovernight.com</a>';
$email_link = '<a href="mailto:support@wpovernight.com">support@wpovernight.com</a>'
?>
<li>
<?php esc_html_e( 'Advanced, customizable templates', 'woocommerce-pdf-invoices-packing-slips' ); ?>
<div class="more" style="display:none;">
<ul>
<li><?php esc_html_e( 'Completely customize the invoice contents (prices, taxes, thumbnails) to your needs with a drag & drop customizer', 'woocommerce-pdf-invoices-packing-slips' ); ?></li>
<li><?php esc_html_e( 'Two extra stylish premade templates (Modern & Business)', 'woocommerce-pdf-invoices-packing-slips' ); ?></li>
<?php /* translators: Premium Templates link */?>
<li><?php printf( esc_html__( "Check out the Premium PDF Invoice & Packing Slips templates at %s.", 'woocommerce-pdf-invoices-packing-slips' ), $template_link ); ?></li>
<?php /* translators: email link */?>
<li><?php printf( esc_html__( "For custom templates, contact us at %s.", 'woocommerce-pdf-invoices-packing-slips' ), $email_link ); ?></li>
</ul>
</div>
</li>
<?php } ?>
</ul>
<?php
// link to hide message when one of the premium extensions is installed
if ( class_exists( 'WooCommerce_PDF_IPS_Pro' ) || class_exists( 'WPO_WCPDF_Templates' ) || class_exists( 'WooCommerce_PDF_IPS_Templates' ) || class_exists( 'WooCommerce_Ext_PrintOrders' ) || class_exists( 'WPO_WC_Smart_Reminder_Emails' ) ) {
printf('<a href="%s" style="display:inline-block; margin-top: 10px;">%s</a>', esc_url( wp_nonce_url( add_query_arg( 'wpo_wcpdf_hide_extensions_ad', 'true' ), 'hide_extensions_ad_nonce' ) ), esc_html__( 'Hide this message', 'woocommerce-pdf-invoices-packing-slips' ) );
}
?>
</div>

View File

@@ -0,0 +1,141 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<?php
$review_url = 'https://wordpress.org/support/plugin/woocommerce-pdf-invoices-packing-slips/reviews/#new-post';
$review_link = sprintf( '<a href="%s">★★★★★</a>', $review_url );
$review_invitation = sprintf(
/* translators: ★★★★★ (5-star) */
__( 'If you like <strong>PDF Invoices & Packing Slips for WooCommerce</strong> please leave us a %s rating. A huge thank you in advance!', 'woocommerce-pdf-invoices-packing-slips' ),
$review_link
);
?>
<script type="text/javascript">
jQuery( function( $ ) {
$("#footer-thankyou").html('<?php echo wp_kses_post( $review_invitation ); ?>');
});
</script>
<div class="wrap">
<div class="icon32" id="icon-options-general"><br /></div>
<h2><?php esc_html_e( 'PDF Invoices & Packing Slips for WooCommerce', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<h2 class="nav-tab-wrapper">
<?php
foreach ( $settings_tabs as $tab_slug => $tab_data ) {
$tab_title = is_array( $tab_data ) ? esc_html( $tab_data['title'] ) : esc_html( $tab_data );
$tab_link = esc_url( "?page=wpo_wcpdf_options_page&tab={$tab_slug}" );
$tab_beta = isset( $tab_data['beta'] ) ? true : false;
if ( $tab_beta ) {
$tab_title .= ' <sup class="wcpdf_beta">beta</sup>';
}
printf( '<a href="%1$s" class="nav-tab nav-tab-%2$s %3$s">%4$s</a>', $tab_link, esc_attr( $tab_slug ), ( ( $active_tab == $tab_slug ) ? 'nav-tab-active' : '' ), $tab_title );
}
?>
</h2>
<?php
do_action( 'wpo_wcpdf_before_settings_page', $active_tab, $active_section );
// save or check option to hide extensions ad
if ( isset( $_REQUEST['wpo_wcpdf_hide_extensions_ad'] ) && isset( $_REQUEST['_wpnonce'] ) ) {
// validate nonce
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'hide_extensions_ad_nonce' ) ) {
wcpdf_log_error( 'You do not have sufficient permissions to perform this action: wpo_wcpdf_hide_extensions_ad' );
$hide_ad = false;
} else {
update_option( 'wpo_wcpdf_hide_extensions_ad', true );
$hide_ad = true;
}
} else {
$hide_ad = get_option( 'wpo_wcpdf_hide_extensions_ad' );
}
if ( ! $hide_ad && ! ( class_exists( 'WooCommerce_PDF_IPS_Pro' ) && class_exists( 'WooCommerce_PDF_IPS_Templates' ) && class_exists( 'WooCommerce_Ext_PrintOrders' ) ) ) {
include( 'extensions.php' );
}
$preview_states = isset( $settings_tabs[$active_tab]['preview_states'] ) ? $settings_tabs[$active_tab]['preview_states'] : 1;
$preview_states_lock = $preview_states == 3 ? false : true;
?>
<div id="wpo-wcpdf-preview-wrapper" data-preview-states="<?php echo esc_attr( $preview_states ); ?>" data-preview-state="closed" data-from-preview-state="" data-preview-states-lock="<?php echo esc_attr( $preview_states_lock ); ?>">
<div class="sidebar">
<form method="post" action="options.php" id="wpo-wcpdf-settings" class="<?php echo esc_attr( "{$active_tab} {$active_section}" ); ?>">
<?php
do_action( 'wpo_wcpdf_before_settings', $active_tab, $active_section );
if ( has_action( "wpo_wcpdf_settings_output_{$active_tab}" ) ) {
do_action( "wpo_wcpdf_settings_output_{$active_tab}", $active_section );
} else {
// legacy settings
settings_fields( "wpo_wcpdf_{$active_tab}_settings" );
do_settings_sections( "wpo_wcpdf_{$active_tab}_settings" );
submit_button();
}
do_action( 'wpo_wcpdf_after_settings', $active_tab, $active_section );
?>
</form>
<?php do_action( 'wpo_wcpdf_after_settings_page', $active_tab, $active_section ); ?>
</div>
<div class="gutter">
<div class="slider slide-left"><span class="gutter-arrow arrow-left"></span></div>
<div class="slider slide-right"><span class="gutter-arrow arrow-right"></span></div>
</div>
<div class="preview-document">
<?php
$documents = WPO_WCPDF()->documents->get_documents( 'enabled', 'any' );
$document_type = 'invoice';
if ( ! empty( $_REQUEST['section'] ) ) {
$document_type = sanitize_text_field( $_REQUEST['section'] );
} elseif ( ! empty( $_REQUEST['preview'] ) ) {
$document_type = sanitize_text_field( $_REQUEST['preview'] );
}
?>
<div class="preview-data-wrapper">
<div class="save-settings"><?php submit_button(); ?></div>
<div class="preview-data preview-order-data">
<div class="preview-order-search-wrapper">
<input type="text" name="preview-order-search" id="preview-order-search" placeholder="<?php esc_html_e( 'ID, email or name', 'woocommerce-pdf-invoices-packing-slips' ); ?>" data-nonce="<?= wp_create_nonce( 'wpo_wcpdf_preview' ); ?>">
<img class="preview-order-search-clear" src="<?php echo WPO_WCPDF()->plugin_url().'/assets/images/reset-input.svg'; ?>" alt="<?php esc_html_e( 'Clear search text', 'woocommerce-pdf-invoices-packing-slips' ); ?>">
</div>
<p class="last-order"><?php esc_html_e( 'Currently showing last order', 'woocommerce-pdf-invoices-packing-slips' ); ?><span class="arrow-down">&#9660;</span></p>
<p class="order-search"><span class="order-search-label"><?php esc_html_e( 'Search for an order', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><span class="arrow-down">&#9660;</span></p>
<ul>
<li class="last-order"><?php esc_html_e( 'Show last order', 'woocommerce-pdf-invoices-packing-slips' ); ?></li>
<li class="order-search"><?php esc_html_e( 'Search for an order', 'woocommerce-pdf-invoices-packing-slips' ); ?></li>
</ul>
<div id="preview-order-search-results"><!-- Results populated with JS --></div>
</div>
<?php if ( $active_tab != 'documents' ) : ?>
<div class="preview-data preview-document-type">
<?php
if ( $document_type ) {
$document = WPO_WCPDF()->documents->get_document( $document_type, null );
if ( ! empty( $document ) ) {
echo '<p class="current"><span class="current-label">'.esc_html( $document->get_title() ).'</span><span class="arrow-down">&#9660;</span></p>';
}
} else {
echo '<p class="current"><span class="current-label">'.__( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' ).'</span><span class="arrow-down">&#9660;</span></p>';
}
?>
<ul class="preview-data-option-list" data-input-name="document_type">
<?php
foreach ( $documents as $document ) {
/* translators: 1. document type, 2. document title */
printf( '<li data-value="%1$s">%2$s</li>', $document->get_type(), $document->get_title() );
}
?>
</ul>
</div>
<?php endif; ?>
</div>
<input type="hidden" name="document_type" data-default="<?php esc_attr_e( $document_type ); ?>" value="<?php esc_attr_e( $document_type ); ?>">
<input type="hidden" name="output_format" value="<?php echo ( isset( $_REQUEST['output_format'] ) && ! empty( $_REQUEST['output_format'] ) ) ? esc_attr( $_REQUEST['output_format'] ) : 'pdf'; ?>">
<input type="hidden" name="order_id" value="">
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce( 'wpo_wcpdf_preview' ); ?>">
<div class="preview"></div>
</div>
</div>
</div>

View File

@@ -0,0 +1,37 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description">
<h2><?php esc_html_e( 'Attach to...', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<p><?php esc_html_e( 'Select to which emails you would like to attach your invoice.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<div class="wpo-setup-input">
<table>
<?php
$current_settings = get_option( 'wpo_wcpdf_documents_settings_invoice', array() );
// load invoice to reuse method to get wc emails
$invoice = wcpdf_get_invoice( null );
$wc_emails = $invoice->get_wc_emails();
foreach ( $wc_emails as $email_id => $name ) {
if ( ! empty( $current_settings['attach_to_email_ids'][$email_id] ) ) {
$checked = 'checked';
} else {
$checked = '';
}
printf(
'<tr>
<th>
<input type="hidden" value="" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][attach_to_email_ids][%1$s]">
<input id="%1$s" type="checkbox" %3$s name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][attach_to_email_ids][%1$s]" value="1">
</th>
<td>
<label for="%1$s" class="checkbox">%2$s</label>
</td>
</tr>',
esc_attr( $email_id ),
esc_html( $name ),
esc_attr( $checked )
);
}
?>
</table>
</div>

View File

@@ -0,0 +1,93 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description">
<h2><?php esc_html_e( 'Display options', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<p><?php esc_html_e( 'Select some additional display options for your invoice.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<div class="wpo-setup-input">
<table>
<?php
$current_settings = get_option( 'wpo_wcpdf_documents_settings_invoice', array() );
?>
<tr>
<th>
<label for="display-shipping-address" class="checkbox"><?php esc_html_e( 'Shipping address', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
</th>
<td>
<input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_shipping_address]" value="">
<select id="display-shipping-address" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_shipping_address]">
<?php
$options = array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'when_different' => __( 'Only when different from billing address' , 'woocommerce-pdf-invoices-packing-slips' ),
'always' => __( 'Always' , 'woocommerce-pdf-invoices-packing-slips' ),
);
foreach ( $options as $slug => $name ) {
$selected = ( ! empty( $current_settings['display_shipping_address'] ) && $current_settings['display_shipping_address'] == $slug ) ? 'selected' : '';
echo '<option value="'.esc_attr( $slug ).'" '.esc_attr( $selected ).'>'.esc_html( $name ).'</option>';
}
?>
</select>
</td>
</tr>
<tr>
<th>
<label for="display-email" class="checkbox"><?php esc_html_e( 'Email address', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
</th>
<td>
<input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_email]" value="">
<input id="display-email" type="checkbox" <?php echo ! empty( $current_settings['display_email'] ) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_email]" value="1">
</td>
</tr>
<tr>
<th>
<label for="display-phone" class="checkbox"><?php esc_html_e( 'Phone number', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
</th>
<td>
<input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_phone]" value="">
<input id="display-phone" type="checkbox" <?php echo ! empty( $current_settings['display_phone'] ) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_phone]" value="1">
</td>
</tr>
<tr>
<th>
<label for="display-date" class="checkbox"><?php esc_html_e( 'Invoice date', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
</th>
<td>
<input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_date]" value="">
<select id="display-date" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_date]">
<?php
$options = array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'invoice_date' => __( 'Invoice Date' , 'woocommerce-pdf-invoices-packing-slips' ),
'order_date' => __( 'Order Date' , 'woocommerce-pdf-invoices-packing-slips' ),
);
foreach ( $options as $slug => $name ) {
$selected = ( ! empty( $current_settings['display_date'] ) && $current_settings['display_date'] == $slug ) ? 'selected' : '';
echo '<option value="'.esc_attr( $slug ).'" '.esc_attr( $selected ).'>'.esc_html( $name ).'</option>';
}
?>
</select>
</td>
<tr>
</tr>
<th>
<label for="display-number" class="checkbox"><?php esc_html_e( 'Invoice number', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
</th>
<td>
<input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_number]" value="">
<select id="display-number" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_number]">
<?php
$options = array(
'' => __( 'No' , 'woocommerce-pdf-invoices-packing-slips' ),
'invoice_number' => __( 'Invoice Number' , 'woocommerce-pdf-invoices-packing-slips' ),
'order_number' => __( 'Order Number' , 'woocommerce-pdf-invoices-packing-slips' ),
);
foreach ( $options as $slug => $name ) {
$selected = ( ! empty( $current_settings['display_number'] ) && $current_settings['display_number'] == $slug ) ? 'selected' : '';
echo '<option value="'.esc_attr( $slug ).'" '.esc_attr( $selected ).'>'.esc_html( $name ).'</option>';
}
?>
</select>
</td>
</tr>
</table>
</div>

View File

@@ -0,0 +1,7 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description wpo-final">
<h1><?php esc_html_e( 'You are good to go!' , 'woocommerce-pdf-invoices-packing-slips' ); ?></h1>
<p><?php esc_html_e( 'If you have any questions please have a look at our documentation:', 'woocommerce-pdf-invoices-packing-slips' ); ?><br>
<a href="https://docs.wpovernight.com/topic/woocommerce-pdf-invoices-packing-slips/" target="_blank"><?php esc_html_e( 'Invoices & Packing Slips' , 'woocommerce-pdf-invoices-packing-slips' ); ?></a></p>
<h2><?php esc_html_e( 'Happy selling!' , 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
</div>

View File

@@ -0,0 +1,18 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description">
<h2><?php esc_html_e( 'Your logo' , 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<p><?php esc_html_e( 'Set the header image that will display on your invoice.' , 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<div class="wpo-setup-input">
<script><?php echo "var wpo_wcpdf_admin = " . wp_json_encode( array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ) . ';'; ?></script>
<?php
WPO_WCPDF()->settings->callbacks->media_upload( array(
'option_name' => 'wpo_wcpdf_settings_general',
'setting_name' => 'wcpdf_settings[wpo_wcpdf_settings_general][header_logo]',
'id' => 'header_logo',
'uploader_title' => __( 'Select or upload your invoice header/logo', 'woocommerce-pdf-invoices-packing-slips' ),
'uploader_button_text' => __( 'Set image', 'woocommerce-pdf-invoices-packing-slips' ),
'remove_button_text' => __( 'Remove image', 'woocommerce-pdf-invoices-packing-slips' ),
) );
?>
</div>

View File

@@ -0,0 +1,16 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description">
<h2><?php esc_html_e( 'Paper format', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<p><?php esc_html_e( 'Select the paper format for your invoice.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<div class="wpo-setup-input">
<?php
$current_settings = wp_parse_args( get_option( 'wpo_wcpdf_settings_general', array() ), array(
'paper_size' => 'a4',
) );
?>
<select name="wcpdf_settings[wpo_wcpdf_settings_general][paper_size]">
<option <?php echo $current_settings['paper_size'] == 'a4' ? 'selected' : ''; ?> value="a4"><?php esc_html_e( 'A4', 'woocommerce-pdf-invoices-packing-slips' ); ?></option>
<option <?php echo $current_settings['paper_size'] == 'letter' ? 'selected' : ''; ?> value="letter"><?php esc_html_e( 'Letter', 'woocommerce-pdf-invoices-packing-slips' ); ?></option>
</select>
</div>

View File

@@ -0,0 +1,15 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description">
<h2><?php esc_html_e( 'Enter your shop name', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<p><?php esc_html_e( 'Lets quickly setup your invoice. Please enter the name and address of your shop in the fields on the right.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
</div>
<div class="wpo-setup-input">
<?php
$current_settings = wp_parse_args( get_option( 'wpo_wcpdf_settings_general', array() ), array(
'shop_name' => array( 'default' => get_bloginfo( 'name' ) ),
'shop_address' => array( 'default' => '' ),
) );
?>
<input type="text" class="shop-name" placeholder="<?php esc_attr_e( 'Shop name', 'woocommerce-pdf-invoices-packing-slips' ); ?>" name="wcpdf_settings[wpo_wcpdf_settings_general][shop_name][default]" value="<?php echo esc_attr( array_pop( $current_settings['shop_name'] ) ); ?>">
<textarea class="shop-address" placeholder="<?php esc_attr_e( 'Shop address', 'woocommerce-pdf-invoices-packing-slips' ); ?>" name="wcpdf_settings[wpo_wcpdf_settings_general][shop_address][default]"><?php echo esc_html( array_pop( $current_settings['shop_address'] ) ); ?></textarea>
</div>

View File

@@ -0,0 +1,19 @@
<?php defined( 'ABSPATH' ) or exit; ?>
<div class="wpo-step-description">
<h2><?php esc_html_e( 'Action buttons', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
<p><?php esc_html_e( 'Would you like to display the action buttons in your WooCommerce order list? The action buttons allow you to manually create a PDF.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
<p><small><?php esc_html_e( '(You can always change this setting later via the Screen Options menu)', 'woocommerce-pdf-invoices-packing-slips' ); ?></small></p>
</div>
<div class="wpo-setup-input">
<?php
$actions = true;
$user_id = get_current_user_id();
$hidden = get_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', true );
if ( empty( $hidden ) )
$hidden = array( 'shipping_address', 'billing_address', 'wc_actions' );
update_user_option( $user_id, 'manageedit-shop_ordercolumnshidden', $hidden, true );
if ( in_array( 'wc_actions', $hidden ) )
$actions = false
?>
<input id="show-action-buttons" type="checkbox" <?php echo $actions !== false ? 'checked' : ''; ?> name="wc_show_action_buttons" value="1"><label for="show-action-buttons" class="checkbox"><?php esc_html_e( 'Show action buttons', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
</div>

View File

@@ -0,0 +1,97 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<style>
#wpo-wcpdf-settings { display: none; }
</style>
<div class="upgrade-table-description">
<h1><?php esc_html_e( 'Wait, there is more...', 'woocommerce-pdf-invoices-packing-slips' ); ?></h1>
<p>
<span><?php esc_html_e( 'A quick overview of the features our PDF Invoices & Packing Slips extensions have to offer.', 'woocommerce-pdf-invoices-packing-slips' ); ?><span>
<span><?php printf( '%s: %s', esc_html_e( 'If you have any questions feel free to send us an email at', 'woocommerce-pdf-invoices-packing-slips' ), '<a href="mailto:support@wpovernight.com">support@wpovernight.com</a>' ); ?><span>
</p>
</div>
<table id="upgrade-table">
<tr>
<th class="first" align="left">&nbsp;</th>
<th align="left"><?php esc_html_e( 'Professional', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
<th align="left"><?php esc_html_e( 'Premium Templates', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
<th align="left"><?php esc_html_e( 'Bundle', 'woocommerce-pdf-invoices-packing-slips' ); ?></th>
<th align="left" class="last">&nbsp;</td>
</tr>
<?php
foreach ( $features as $feature ) {
echo '<tr><td class="first feature-label">' . $feature['label'];
echo ! empty( $feature['description'] ) ? '<br><span class="description">' . $feature['description'] . '</span></td>' : '</td>';
foreach ( ['pro', 'templates', 'bundle'] as $extension ) {
echo in_array( $extension, $feature['extensions'] ) ? '<td><span class="feature-available"></span></td>' : '<td>-</td>';
}
echo '<td align="left" class="last">&nbsp;</td></tr>';
}
?>
<tr class="upgrade-links">
<td class="first" align="left">&nbsp;</td>
<?php
$extensions_disabled = [];
$extensions_enabled = [];
$extension_columns = [];
// pro, templates & bundle columns
foreach ( $extension_license_infos as $extension => $info ) {
// enabled
if ( WPO_WCPDF()->settings->upgrade->extension_is_enabled( $extension ) ) {
$extensions_enabled[] = $extension;
$title = __( 'Currently installed', 'woocommerce-pdf-invoices-packing-slips' );
if ( empty( $info['status'] ) || $info['status'] != 'valid' ) {
$subtitle = sprintf(
/* translators: learn more link */
__( 'License not yet activated: %s', 'woocommerce-pdf-invoices-packing-slips' ),
'<a href="https://docs.wpovernight.com/general/installing-wp-overnight-plugins/#activating-your-license" target="_blank">'.__( 'Learn more', 'woocommerce-pdf-invoices-packing-slips' ).'</a>'
);
} else {
$subtitle = '';
}
$extension_columns[$extension] = sprintf(
'<td align="left"><h4>%s</h4><p>%s</p></td>',
$title,
$subtitle
);
// disabled (includes bundle)
} else {
$extensions_disabled[] = $extension;
if ( $info['url'] == 'is_bundled' ) { // extension license is bundled, no need to buy
$extension_columns[$extension] = '<td align="left">&nbsp;</td>';
} else {
$extension_columns[$extension] = sprintf(
'<td align="left"><a class="upgrade_button" href="%s" target="_blank">%s</a></td>',
esc_url_raw( $info['url'] ),
__( 'Upgrade now', 'woocommerce-pdf-invoices-packing-slips' )
);
}
}
}
// maybe disable 1 extension or bundle column
foreach ( $extensions_disabled as $extension_disabled ) {
if ( ( count( $extensions_disabled ) < 3 && $extension_disabled != 'bundle' ) || ( count( $extensions_disabled ) == 1 && $extension_disabled == 'bundle' ) ) {
$extension_columns[$extension_disabled] = '<td align="left">&nbsp;</td>';
}
}
foreach ( $extension_columns as $column ) {
echo $column;
}
?>
<td align="left" class="last">&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,423 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/*
|--------------------------------------------------------------------------
| Document getter functions
|--------------------------------------------------------------------------
|
| Global functions to get the document object for an order
|
*/
function wcpdf_filter_order_ids( $order_ids, $document_type ) {
$order_ids = apply_filters( 'wpo_wcpdf_process_order_ids', $order_ids, $document_type );
// filter out trashed orders.
foreach ( $order_ids as $key => $order_id ) {
$order = wc_get_order( $order_id );
if ( ! empty( $order ) && is_callable( array( $order, 'get_status' ) ) && $order->get_status() == 'trash' ) {
unset( $order_ids[ $key ] );
}
}
return $order_ids;
}
function wcpdf_get_document( $document_type, $order, $init = false ) {
// $order can be one of the following:
// - WC Order object
// - array of order ids
// - null if order not loaded or loaded later
if ( ! empty( $order ) ) {
if ( ! is_object( $order ) && ! is_array( $order ) && is_numeric( $order ) ) {
$order = array( absint( $order ) ); // convert single order id to array.
}
if ( is_object( $order ) ) {
// we filter order_ids for objects too:
// an order object may need to be converted to several refunds for example.
$order_ids = array( $order->get_id() );
$filtered_order_ids = wcpdf_filter_order_ids( $order_ids, $document_type );
// check if something has changed.
$order_id_diff = array_diff( $filtered_order_ids, $order_ids );
if ( empty( $order_id_diff ) && count( $order_ids ) == count( $filtered_order_ids ) ) {
// nothing changed, load document with Order object.
do_action( 'wpo_wcpdf_process_template_order', $document_type, $order->get_id() );
$document = WPO_WCPDF()->documents->get_document( $document_type, $order );
if ( ! $document || ! is_callable( array( $document, 'is_allowed' ) ) || ! $document->is_allowed() ) {
return false;
}
if ( $init && ! $document->exists() ) {
$document->init();
$document->save();
}
return $document;
} else {
// order ids array changed, continue processing that array.
$order_ids = $filtered_order_ids;
}
} elseif ( is_array( $order ) ) {
$order_ids = wcpdf_filter_order_ids( $order, $document_type );
} else {
return false;
}
if ( empty( $order_ids ) ) {
// No orders to export for this document type.
return false;
}
// if we only have one order, it's simple.
if ( count( $order_ids ) == 1 ) {
$order_id = array_pop( $order_ids );
do_action( 'wpo_wcpdf_process_template_order', $document_type, $order_id );
$order = wc_get_order( $order_id );
$document = WPO_WCPDF()->documents->get_document( $document_type, $order );
if ( ! $document->is_allowed() ) {
return false;
}
if ( $init && ! $document->exists() ) {
$document->init();
$document->save();
}
// otherwise we use bulk class to wrap multiple documents in one.
} else {
$document = wcpdf_get_bulk_document( $document_type, $order_ids );
}
} else {
// orderless document (used as wrapper for bulk, for example).
$document = WPO_WCPDF()->documents->get_document( $document_type, $order );
}
return $document;
}
function wcpdf_get_bulk_document( $document_type, $order_ids ) {
return new \WPO\WC\PDF_Invoices\Documents\Bulk_Document( $document_type, $order_ids );
}
function wcpdf_get_invoice( $order, $init = false ) {
return wcpdf_get_document( 'invoice', $order, $init );
}
function wcpdf_get_packing_slip( $order, $init = false ) {
return wcpdf_get_document( 'packing-slip', $order, $init );
}
function wcpdf_get_bulk_actions() {
$actions = array();
$documents = WPO_WCPDF()->documents->get_documents( 'enabled', 'any' );
foreach ( $documents as $document ) {
foreach ( $document->output_formats as $output_format ) {
$slug = $document->get_type();
if ( 'pdf' !== $output_format ) {
$slug .= "_{$output_format}";
}
if ( $document->is_enabled( $output_format ) ) {
$actions[$slug] = strtoupper( $output_format ) . ' ' . $document->get_title();
}
}
}
return apply_filters( 'wpo_wcpdf_bulk_actions', $actions );
}
/**
* Load HTML into (pluggable) PDF library, DomPDF 1.0.2 by default
* Use wpo_wcpdf_pdf_maker filter to change the PDF class (which can wrap another PDF library).
*
* @param string $html
* @param array $settings
* @param null|object $document
* @return WPO\WC\PDF_Invoices\Makers\PDF_Maker
*/
function wcpdf_get_pdf_maker( $html, $settings = array(), $document = null ) {
$class = ( defined( 'WPO_WCPDF_VERSION' ) && version_compare( WPO_WCPDF_VERSION, '3.7.0-beta-1', '<' ) ) ? '\\WPO\\WC\\PDF_Invoices\\PDF_Maker' : '\\WPO\\WC\\PDF_Invoices\\Makers\\PDF_Maker';
if ( ! class_exists( $class ) ) {
include_once( WPO_WCPDF()->plugin_path() . '/includes/makers/class-pdf-maker.php' );
}
$class = apply_filters( 'wpo_wcpdf_pdf_maker', $class );
return new $class( $html, $settings, $document );
}
/**
* Get UBL Maker
* Use wpo_wcpdf_ubl_maker filter to change the UBL class (which can wrap another UBL library).
*
* @return WPO\WC\PDF_Invoices\Makers\UBL_Maker
*/
function wcpdf_get_ubl_maker() {
$class = '\\WPO\\WC\\PDF_Invoices\\Makers\\UBL_Maker';
if ( ! class_exists( $class ) ) {
include_once( WPO_WCPDF()->plugin_path() . '/includes/makers/class-ubl-maker.php' );
}
$class = apply_filters( 'wpo_wcpdf_ubl_maker', $class );
return new $class();
}
/**
* Check if the default PDF maker is used for creating PDF
*
* @return bool whether the PDF maker is the default or not
*/
function wcpdf_pdf_maker_is_default() {
$default_pdf_maker = ( defined( 'WPO_WCPDF_VERSION' ) && version_compare( WPO_WCPDF_VERSION, '3.7.0-beta-1', '<' ) ) ? '\\WPO\\WC\\PDF_Invoices\\PDF_Maker' : '\\WPO\\WC\\PDF_Invoices\\Makers\\PDF_Maker';
return $default_pdf_maker == apply_filters( 'wpo_wcpdf_pdf_maker', $default_pdf_maker );
}
function wcpdf_pdf_headers( $filename, $mode = 'inline', $pdf = null ) {
switch ( $mode ) {
case 'download':
header( 'Content-Description: File Transfer' );
header( 'Content-Type: application/pdf' );
header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Connection: Keep-Alive' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Pragma: public' );
break;
case 'inline':
default:
header( 'Content-type: application/pdf' );
header( 'Content-Disposition: inline; filename="' . $filename . '"' );
break;
}
do_action( 'wpo_wcpdf_headers', $filename, $mode, $pdf );
}
function wcpdf_ubl_headers( $filename, $size ) {
header( 'Content-Description: File Transfer' );
header( 'Content-Type: text/xml' );
header( 'Content-Disposition: attachment; filename=' . $filename );
header( 'Content-Transfer-Encoding: binary' );
header( 'Connection: Keep-Alive' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Pragma: public' );
header( 'Content-Length: ' . $size );
do_action( 'wpo_after_ubl_headers', $filename, $size );
}
/**
* Wrapper for deprecated functions so we can apply some extra logic.
*
* @since 2.0
* @param string $function
* @param string $version
* @param string $replacement
*/
function wcpdf_deprecated_function( $function, $version, $replacement = null ) {
if ( apply_filters( 'wcpdf_disable_deprecation_notices', false ) ) {
return;
}
// if the deprecated function is called from one of our filters, $this should be $document.
$filter = current_filter();
$global_wcpdf_filters = array( 'wp_ajax_generate_wpo_wcpdf' );
if ( ! empty( $filter ) && ! empty( $replacement ) && ! in_array( $filter, $global_wcpdf_filters ) && false !== strpos( $filter, 'wpo_wcpdf' ) && false !== strpos( $replacement, '$this' ) ) {
$replacement = str_replace( '$this', '$document', $replacement );
$replacement = "{$replacement} - check that the \$document parameter is included in your action or filter ($filter)!";
}
$is_ajax = function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX;
if ( $is_ajax ) {
do_action( 'deprecated_function_run', $function, $replacement, $version );
$log_string = "The {$function} function is deprecated since version {$version}.";
$log_string .= $replacement ? " Replace with {$replacement}." : '';
error_log( $log_string );
wcpdf_log_error( $log_string, 'warning' );
} else {
_deprecated_function( $function, $version, $replacement );
}
}
/**
* Logger function to capture errors thrown by this plugin, uses the WC Logger when possible (WC3.0+)
*/
function wcpdf_log_error( $message, $level = 'error', $e = null ) {
if ( function_exists( 'wc_get_logger' ) ) {
$logger = wc_get_logger();
$context = array( 'source' => 'wpo-wcpdf' );
if ( is_callable( array( $e, 'getFile' ) ) && is_callable( array( $e, 'getLine' ) ) ) {
$message = sprintf( '%s (%s:%d)', $message, $e->getFile(), $e->getLine() );
}
if ( apply_filters( 'wcpdf_log_stacktrace', false ) && is_callable( array( $e, 'getTraceAsString' ) ) ) {
$message .= "\n" . $e->getTraceAsString();
}
// The `log` method accepts any valid level as its first argument.
// debug - 'Detailed debug information'
// info - 'Interesting events'
// notice - 'Normal but significant events'
// warning - 'Exceptional occurrences that are not errors'
// error - 'Runtime errors that do not require immediate'
// critical - 'Critical conditions'
// alert - 'Action must be taken immediately'
// emergency - 'System is unusable'.
$logger->log( $level, $message, $context );
} else {
error_log( "WCPDF error ({$level}): {$message}" );
}
}
function wcpdf_output_error( $message, $level = 'error', $e = null ) {
if ( ! current_user_can( 'edit_shop_orders' ) ) {
esc_html_e( 'Error creating PDF, please contact the site owner.', 'woocommerce-pdf-invoices-packing-slips' );
return;
}
?>
<div style="border: 2px solid red; padding: 5px;">
<h3><?php echo wp_kses_post( $message ); ?></h3>
<?php if ( is_callable( array( $e, 'getFile' ) ) && is_callable( array( $e, 'getLine' ) ) ): ?>
<pre><?php echo esc_html( $e->getFile() ); ?> (<?php echo esc_html( $e->getLine() ); ?>)</pre>
<?php endif ?>
<?php if ( is_callable( array( $e, 'getTraceAsString' ) ) ) : ?>
<pre><?php echo esc_html( $e->getTraceAsString() ); ?></pre>
<?php endif ?>
</div>
<?php
}
/**
* Date formatting function
*
* @param object $document
* @param string $date_type Optional. A date type to be filtered eg. 'invoice_date', 'order_date_created', 'order_date_modified', 'order_date', 'order_date_paid', 'order_date_completed', 'current_date', 'document_date', 'packing_slip_date'.
*/
function wcpdf_date_format( $document = null, $date_type = null ) {
return apply_filters( 'wpo_wcpdf_date_format', wc_date_format(), $document, $date_type );
}
/**
* Catch MySQL errors
*
* Inspired from here: https://github.com/johnbillion/query-monitor/blob/d5b622b91f18552e7105e62fa84d3102b08975a4/collectors/db_queries.php#L125-L280
*
* With SAVEQUERIES constant defined as 'false', '$wpdb->queries' is empty and '$EZSQL_ERROR' is used instead.
* Using the Query Monitor plugin, the SAVEQUERIES constant is defined as 'true'
* More info about this constant can be found here: https://wordpress.org/support/article/debugging-in-wordpress/#savequeries
*
* @param object $wpdb
* @return array errors found
*/
function wcpdf_catch_db_object_errors( $wpdb ) {
global $EZSQL_ERROR;
$errors = array();
// using '$wpdb->queries'.
if ( ! empty( $wpdb->queries ) && is_array( $wpdb->queries ) ) {
foreach ( $wpdb->queries as $query ) {
$result = isset( $query['result'] ) ? $query['result'] : null;
if ( is_wp_error( $result ) && is_array( $result->errors ) ) {
foreach ( $result->errors as $error ) {
$errors[] = reset( $error );
}
}
}
}
// fallback to '$EZSQL_ERROR'.
if ( empty( $errors ) && ! empty( $EZSQL_ERROR ) && is_array( $EZSQL_ERROR ) ) {
foreach ( $EZSQL_ERROR as $error ) {
$errors[] = $error['error_str'];
}
}
// log errors.
if ( ! empty( $errors ) ) {
foreach ( $errors as $error_message ) {
wcpdf_log_error( $error_message, 'critical' );
}
}
return $errors;
}
/**
* String convert encoding.
*
* @param string $string
* @param string $tool
* @return string
*/
function wcpdf_convert_encoding( $string, $tool = 'mb_convert_encoding' ) {
if ( empty( $string ) ) {
return $string;
}
$tool = apply_filters( 'wpo_wcpdf_convert_encoding_tool', $tool );
$from_encoding = apply_filters( 'wpo_wcpdf_convert_from_encoding', 'UTF-8', $tool );
switch ( $tool ) {
case 'mb_convert_encoding':
$to_encoding = apply_filters( 'wpo_wcpdf_convert_to_encoding', 'HTML-ENTITIES', $tool );
// provided by composer 'symfony/polyfill-mbstring' library.
// it uses 'iconv()', must have 'libiconv' configured instead of 'glibc' library.
if ( class_exists( '\\Symfony\\Polyfill\\Mbstring\\Mbstring' ) ) {
$string = \Symfony\Polyfill\Mbstring\Mbstring::mb_convert_encoding( $string, $to_encoding, $from_encoding );
}
break;
case 'uconverter':
$to_encoding = apply_filters( 'wpo_wcpdf_convert_to_encoding', 'HTML-ENTITIES', $tool );
// only for PHP 8.2+.
if ( version_compare( PHP_VERSION, '8.1', '>' ) && class_exists( 'UConverter' ) && extension_loaded( 'intl' ) ) {
$string = UConverter::transcode( $string, $to_encoding, $from_encoding );
}
break;
case 'iconv':
$to_encoding = apply_filters( 'wpo_wcpdf_convert_to_encoding', 'ISO-8859-1', $tool );
// provided by composer 'symfony/polyfill-iconv' library.
if ( class_exists( '\\Symfony\\Polyfill\\Iconv\\Iconv' ) ) {
$string = \Symfony\Polyfill\Iconv\Iconv::iconv( $from_encoding, $to_encoding, $string );
// default server library.
// must have 'libiconv' configured instead of 'glibc' library.
} elseif ( function_exists( 'iconv' ) ) {
$string = iconv( $from_encoding, $to_encoding, $string );
}
break;
}
return $string;
}
/**
* Safe redirect or die.
*
* @param string $url
* @param string|WP_Error $message
* @return void
*/
function wcpdf_safe_redirect_or_die( $url = '', $message = '' ) {
if ( ! empty( $url ) ) {
wp_safe_redirect( $url );
exit;
} else {
wp_die( $message );
}
}
function WPO_WCPDF_Legacy() {
return \WPO\WC\PDF_Invoices\Legacy\WPO_WCPDF_Legacy::instance();
}