f_invoice_number_data & _wcpdf_invoice_date are duplicates of the below and therefore not included
'_wcpdf_invoice_number' => esc_html__( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ),
'_wcpdf_invoice_date_formatted' => esc_html__( 'Invoice Date', 'woocommerce-pdf-invoices-packing-slips' ),
);
return $meta_to_export + $private_address_meta;
}
/**
* Set the default PHPMailer validator to 'php' ( which uses filter_var($address, FILTER_VALIDATE_EMAIL) )
* This avoids issues with the presence of attachments affecting email address validation in some distros of PHP 7.3
* See: https://wordpress.org/support/topic/invalid-address-setfrom/#post-11583815
* Fixed in WP5.5 due to upgrade to newer PHPMailer
*/
public function set_phpmailer_validator( $mailArray ) {
if ( version_compare( get_bloginfo( 'version' ), '5.5-dev', '<' ) ) {
global $phpmailer;
if ( ! ( $phpmailer instanceof \PHPMailer ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
require_once ABSPATH . WPINC . '/class-smtp.php';
$phpmailer = new \PHPMailer( true );
}
$phpmailer::$validator = 'php';
}
return $mailArray;
}
/**
* Log document creation to order notes
*
* @param object $document
* @param string $trigger
*
* @return void
*/
public function log_document_creation_to_order_notes( object $document, string $trigger ) {
if ( empty( $document ) || empty( $trigger ) || ! isset( WPO_WCPDF()->settings->debug_settings['log_to_order_notes'] ) ) {
return;
}
$triggers = $this->get_document_triggers();
if ( ! array_key_exists( $trigger, $triggers ) ) {
return;
}
$user_note = '';
$manual_triggers = $this->get_document_triggers( 'manual' );
// Add user information if the trigger is manual.
if ( array_key_exists( $trigger, $manual_triggers ) ) {
$user = wp_get_current_user();
if ( ! empty( $user->user_login ) ) {
$user_note = sprintf(
' (%s: %s)',
__( 'User', 'woocommerce-pdf-invoices-packing-slips' ),
esc_html( $user->user_login )
);
}
}
$note = sprintf(
/* translators: 1. document title, 2. creation trigger */
__( 'PDF %1$s created via %2$s.', 'woocommerce-pdf-invoices-packing-slips' ),
$document->get_title(),
$triggers[ $trigger ]
);
$this->log_to_order_notes( $note . $user_note, $document );
}
/**
* Log document deletion to order notes.
*
* @param object $document
*
* @return void
*/
public function log_document_deletion_to_order_notes( object $document ): void {
if ( ! empty( WPO_WCPDF()->settings->debug_settings['log_to_order_notes'] ) ) {
$user_note = '';
$user = wp_get_current_user();
if ( ! empty( $user->user_login ) ) {
$user_note = sprintf(
' (%s: %s)',
__( 'User', 'woocommerce-pdf-invoices-packing-slips' ),
esc_html( $user->user_login )
);
}
$note = sprintf(
/* translators: document title */
__( 'PDF %s deleted.', 'woocommerce-pdf-invoices-packing-slips' ),
$document->get_title()
);
$this->log_to_order_notes( $note . $user_note, $document );
}
}
/**
* Log document printed to order notes
*
* @param object $document
* @param string $trigger
* @return void
*/
public function log_document_printed_to_order_notes( $document, $trigger ) {
$triggers = array_merge(
[ 'manually' => __( 'manually', 'woocommerce-pdf-invoices-packing-slips' ) ],
$this->get_document_triggers()
);
if ( ! empty( $document ) && isset( WPO_WCPDF()->settings->debug_settings['log_to_order_notes'] ) && ! empty( $trigger ) && array_key_exists( $trigger, $triggers ) ) {
/* translators: 1. document title, 2. creation trigger */
$message = __( '%1$s document marked as printed via %2$s.', 'woocommerce-pdf-invoices-packing-slips' );
$note = sprintf( $message, $document->get_title(), $triggers[$trigger] );
$this->log_to_order_notes( $note, $document );
}
}
/**
* Log document unmark printed to order notes
*
* @param object $document
* @param string $trigger
* @return void
*/
public function log_unmark_document_printed_to_order_notes( $document ) {
if ( ! empty( $document ) && isset( WPO_WCPDF()->settings->debug_settings['log_to_order_notes'] ) ) {
/* translators: 1. document title, 2. creation trigger */
$message = __( '%1$s document unmark printed.', 'woocommerce-pdf-invoices-packing-slips' );
$note = sprintf( $message, $document->get_title() );
$this->log_to_order_notes( $note, $document );
}
}
/**
* Logs to the order notes
*
* @param string $note
* @param object $document
* @return void
*/
public function log_to_order_notes( $note, $document ) {
if ( property_exists( $document, 'order_ids' ) && ! empty( $document->order_ids ) ) { // bulk document
$order_ids = $document->order_ids;
} else {
$order_ids = [ $document->order->get_id() ];
}
foreach ( $order_ids as $order_id ) {
$order = wc_get_order( $order_id );
if ( empty( $order ) ) {
continue;
}
if ( is_callable( array( $order, 'add_order_note' ) ) ) { // order
$order->add_order_note( wp_strip_all_tags( $note ) );
} elseif ( $document->is_refund( $order ) ) { // refund order
$parent_order = $document->get_refund_parent( $order );
if ( ! empty( $parent_order ) && is_callable( array( $parent_order, 'add_order_note' ) ) ) {
$parent_order->add_order_note( wp_strip_all_tags( $note ) );
}
}
}
}
/**
* Logs to the order meta
*
* @param object $document
* @param string $trigger
* @param boolean $force
* @param array|null $request
* @return void
*/
public function log_document_creation_trigger_to_order_meta( $document, $trigger, $force = false, $request = null ) {
if ( $trigger == 'bulk' && property_exists( $document, 'order_ids' ) && ! empty( $document->order_ids ) ) { // bulk document
$order_ids = $document->order_ids;
} elseif ( ! is_null( $document->order ) && is_callable( array( $document->order, 'get_id' ) ) ) {
$order_ids = array( $document->order->get_id() );
} elseif ( isset( $request['order_id'] ) ) {
$order_ids = array( absint( $request['order_id'] ) );
} else {
$order_ids = array();
}
if ( ! empty( $order_ids ) ) {
foreach ( $order_ids as $order_id ) {
$order = wc_get_order( $order_id );
if ( ! empty( $order ) ) {
if ( is_callable( [ $document, 'get_type' ] ) && $document->get_type() == 'credit-note' && is_callable( [ $order, 'get_parent_id' ] ) ) {
$order = wc_get_order( $order->get_parent_id() );
}
if ( empty( $order ) ) {
continue;
}
$status = $order->get_meta( "_wcpdf_{$document->slug}_creation_trigger" );
if ( true == $force || empty( $status ) ) {
$order->update_meta_data( "_wcpdf_{$document->slug}_creation_trigger", $trigger );
$order->save_meta_data();
}
}
}
}
}
/**
* Get the document triggers
*
* @param string $trigger_type The trigger type: 'manual', 'automatic', or 'all'. Defaults to 'all'.
*
* @return array
*/
public function get_document_triggers( string $trigger_type = 'all' ): array {
$manual_triggers = apply_filters( 'wpo_wcpdf_manual_document_triggers', array(
'single' => __( 'single order action', 'woocommerce-pdf-invoices-packing-slips' ),
'bulk' => __( 'bulk order action', 'woocommerce-pdf-invoices-packing-slips' ),
'my_account' => __( 'my account', 'woocommerce-pdf-invoices-packing-slips' ),
'document_data' => __( 'order document data (number and/or date set manually)', 'woocommerce-pdf-invoices-packing-slips' ),
) );
$automatic_triggers = apply_filters( 'wpo_wcpdf_automatic_document_triggers', array(
'email_attachment' => __( 'email attachment', 'woocommerce-pdf-invoices-packing-slips' ),
) );
switch ( $trigger_type ) {
case 'manual':
$triggers = $manual_triggers;
break;
case 'automatic':
$triggers = $automatic_triggers;
break;
case 'all':
default:
$triggers = array_merge( $manual_triggers, $automatic_triggers );
break;
}
return apply_filters( 'wpo_wcpdf_document_triggers', $triggers, $trigger_type );
}
/**
* Mark document printed
*
* @return void
*/
public function mark_document_printed( $document, $trigger ) {
$triggers = isset( $document->latest_settings['mark_printed'] ) && is_array( $document->latest_settings['mark_printed'] ) ? $document->latest_settings['mark_printed'] : [];
if ( ! empty( $document ) && ! $this->is_document_printed( $document ) ) {
if ( ! empty( $order = $document->order ) && ! empty( $trigger ) && in_array( $trigger, $triggers ) && apply_filters( 'wpo_wcpdf_allow_mark_document_printed', true, $document, $trigger ) ) {
if ( 'shop_order' === $order->get_type() ) {
$data = [
'date' => time(),
'trigger' => $trigger,
];
$order->update_meta_data( "_wcpdf_{$document->slug}_printed", $data );
$order->save_meta_data();
$this->log_document_printed_to_order_notes( $document, $trigger );
}
}
}
}
/**
* Unmark document printed
*
* @return void
*/
public function unmark_document_printed( $document ) {
if ( ! empty( $document ) && $this->is_document_printed( $document ) ) {
if ( ! empty( $order = $document->order ) && apply_filters( 'wpo_wcpdf_allow_unmark_document_printed', true, $document ) ) {
$meta_key = "_wcpdf_{$document->slug}_printed";
if ( 'shop_order' === $order->get_type() && ! empty( $order->get_meta( $meta_key ) ) ) {
$order->delete_meta_data( $meta_key );
$order->save_meta_data();
$this->log_unmark_document_printed_to_order_notes( $document );
}
}
}
}
/**
* AJAX request for mark/unmark document printed
*
* @return void
*/
public function document_printed_ajax() {
check_ajax_referer( 'printed_wpo_wcpdf', 'security' );
$data = stripslashes_deep( $_REQUEST );
$error = 0;
if ( ! empty( $data['action'] ) && $data['action'] == "printed_wpo_wcpdf" && ! empty( $data['event'] ) && ! empty( $data['document_type'] ) && ! empty( $data['order_id'] ) && ! empty( $data['trigger'] ) ) {
$document = wcpdf_get_document( esc_attr( $data['document_type'] ), esc_attr( $data['order_id'] ) );
$full_permission = WPO_WCPDF()->admin->user_can_manage_document( esc_attr( $data['document_type'] ) );
if ( ! empty( $document ) && ! empty( $order = $document->order ) && $full_permission ) {
switch ( esc_attr( $data['event'] ) ) {
case 'mark':
$this->mark_document_printed( $document, esc_attr( $data['trigger'] ) );
break;
case 'unmark':
$this->unmark_document_printed( $document );
break;
}
if ( is_callable( [ $order, 'get_edit_order_url' ] ) ) {
wp_safe_redirect( $order->get_edit_order_url() );
} else {
wp_safe_redirect( admin_url( 'post.php?action=edit&post=' . esc_attr( $data['order_id'] ) ) );
}
} else {
$error++;
}
} else {
$error++;
}
if ( $error > 0 ) {
wp_die(
sprintf(
/* translators: 1. document type, 2. mark/unmark */
esc_html__( 'Document of type %1$s for the selected order could not be marked as printed.', 'woocommerce-pdf-invoices-packing-slips' ),
esc_attr( $data['document_type'] )
)
);
}
}
/**
* Check if a document is printed
*
* @return bool
*/
public function is_document_printed( $document ) {
$is_printed = false;
if ( ! empty( $document ) && ! empty( $order = $document->order ) ) {
if ( 'shop_order' === $order->get_type() && ! empty( $printed_data = $order->get_meta( "_wcpdf_{$document->slug}_printed" ) ) ) {
$is_printed = true;
}
}
return $is_printed;
}
/**
* Check if a document can be manually marked as printed
*
* @return bool
*/
public function document_can_be_manually_marked_printed( $document ) {
$can_be_manually_marked_printed = false;
if ( empty( $document ) || ( property_exists( $document, 'is_bulk' ) && $document->is_bulk ) ) {
return $can_be_manually_marked_printed;
}
$document->save_settings();
$can_be_manually_marked_printed = false;
$document_exists = is_callable( array( $document, 'exists' ) ) ? $document->exists() : false;
$document_printed = $document_exists && is_callable( array( $document, 'printed' ) ) ? $document->printed() : false;
$triggers = isset( $document->latest_settings['mark_printed'] ) && is_array( $document->latest_settings['mark_printed'] ) ? $document->latest_settings['mark_printed'] : [];
$manually_print_enabled = in_array( 'manually', $triggers ) ? true : false;
if ( $document_exists && ! $document_printed && $manually_print_enabled ) {
$can_be_manually_marked_printed = true;
}
return apply_filters( 'wpo_wcpdf_document_can_be_manually_marked_printed', $can_be_manually_marked_printed, $document );
}
/**
* Get document printed data
*
* @return array
*/
public function get_document_printed_data( $document ) {
$data = [];
if ( ! empty( $document ) && $this->is_document_printed( $document ) && ! empty( $order = $document->order ) ) {
if ( 'shop_order' === $order->get_type() && ! empty( $printed_data = $order->get_meta( "_wcpdf_{$document->slug}_printed" ) ) ) {
$data = $printed_data;
}
}
return apply_filters( 'wpo_wcpdf_document_printed_data', $data, $document );
}
/**
* Enable error logging for administrators.
*/
public function enable_debug() {
if ( \WPO_WCPDF()->settings->user_can_manage_settings() ) {
error_reporting( E_ALL ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting
ini_set( 'display_errors', 1 ); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged
}
}
public function wc_webhook_topic_hooks( $topic_hooks, $wc_webhook ) {
$documents = WPO_WCPDF()->documents->get_documents();
foreach ($documents as $document) {
$topic_hooks["order.{$document->type}-saved"] = array(
"wpo_wcpdf_webhook_order_{$document->slug}_saved",
);
}
return $topic_hooks;
}
/**
* Adds custom webhook topic events.
*
* @param array $topic_events
*
* @return array
*/
public function wc_webhook_topic_events( array $topic_events = array() ): array {
$documents = WPO_WCPDF()->documents->get_documents();
foreach ( $documents as $document ) {
$topic_events[] = "{$document->type}-saved";
}
return $topic_events;
}
public function wc_webhook_topics( $topics ) {
$documents = WPO_WCPDF()->documents->get_documents();
foreach ($documents as $document) {
/* translators: document title */
$topics["order.{$document->type}-saved"] = esc_html( sprintf( __( 'Order %s Saved', 'woocommerce-pdf-invoices-packing-slips' ), $document->get_title() ) );
}
return $topics;
}
public function wc_webhook_trigger( $document, $order ) {
$this->reload_wpo_custom_webhooks();
do_action( "wpo_wcpdf_webhook_order_{$document->slug}_saved", $order->get_id() );
}
/**
* Reloads WooCommerce PDF Invoices webhooks to ensure custom hooks are processed.
*
* This function introduced to resolve an issue where WooCommerce
* webhooks were not enqueuing our plugin's custom hooks.
* The root cause is that the `wc_webhook_topic_hooks()` function, responsible
* for modifying hooks, is not executed in time. The `add_filter()` call that
* registers `wc_webhook_topic_hooks()` is executed after `apply_filters()`,
* preventing the `wpo_wcpdf_webhook_order_{$document->slug}_saved` action hook
* from being included in the list of webhook topics.
*
* https://github.com/wpovernight/woocommerce-pdf-invoices-packing-slips/issues/1083
*
* @return void
*/
private function reload_wpo_custom_webhooks() {
if (
! apply_filters( 'wpo_wcpdf_reload_wpo_custom_webhooks', true ) ||
! class_exists( 'WC_Data_Store' ) ||
! class_exists( 'WC_Webhook' )
) {
return;
}
$wpo_topic_hooks = $this->wc_webhook_topic_events();
$data_store = \WC_Data_Store::load( 'webhook' );
$webhooks = $data_store->get_webhooks_ids( 'active' );
if ( empty( $webhooks ) ) {
return;
}
foreach ( $webhooks as $webhook_id ) {
$webhook = new \WC_Webhook( $webhook_id );
if ( $webhook->get_pending_delivery() ) {
continue;
}
$webhook_topic = $webhook->get_topic();
if ( empty( $webhook_topic ) || ! is_string( $webhook_topic ) ) {
continue;
}
$topic = str_replace( 'order.', '', $webhook_topic );
if ( in_array( $topic, $wpo_topic_hooks, true ) ) {
$webhook->enqueue();
}
}
}
/**
* Display due date table row in the order data section for legacy templates.
*
* @param null|string $document_type
* @param null|\WC_Abstract_Order $order
*
* @return void
*/
public function display_due_date_table_row( ?string $document_type = null, ?\WC_Abstract_Order $order = null ): void {
if ( empty( $order ) || empty( $document_type ) ) {
return;
}
$current_template_path = explode( '/', WPO_WCPDF()->settings->get_template_path() );
$current_template = end( $current_template_path );
$premium_templates = array( 'Simple Premium', 'Modern', 'Business' );
// Return if the Simple template is selected. Due date is displayed through template.
if ( 'Simple' === $current_template ) {
return;
}
// Return if the Updated Premium Template is selected. Due date is displayed through template.
if (
function_exists( 'WPO_WCPDF_Templates' ) &&
version_compare( WPO_WCPDF_Templates()->version, '2.21.9', '>' ) &&
in_array( $current_template, $premium_templates, true )
) {
return;
}
$document = wcpdf_get_document( $document_type, $order );
if ( ! $document ) {
return;
}
$due_date_timestamp = is_callable( array( $document, 'get_due_date' ) ) ? $document->get_due_date() : 0;
if ( 0 >= $due_date_timestamp ) {
return;
}
$due_date = apply_filters_deprecated(
'wpo_wcpdf_due_date_display',
array(
date_i18n( wcpdf_date_format( $this, 'due_date' ), $due_date_timestamp ),
$due_date_timestamp,
$document_type,
$document
),
'3.9.0',
'wpo_wcpdf_document_due_date'
);
$due_date_title = is_callable( array( $document, 'get_due_date_title' ) ) ?
$document->get_due_date_title() : __( 'Due Date:', 'woocommerce-pdf-invoices-packing-slips' );
if ( ! empty( $due_date ) ) {
echo '
| ', esc_html( $due_date_title ), ' |
', esc_html( $due_date ), ' |
';
}
}
public function handle_document_link_in_emails(): void {
$email_hooks = array();
$documents = WPO_WCPDF()->documents->get_documents();
foreach ( $documents as $document ) {
$document_settings = WPO_WCPDF()->settings->get_document_settings( $document->get_type(), 'pdf' );
$email_placement = $document_settings['include_email_link_placement'] ?? '';
if ( ! empty( $email_placement ) ) {
$email_hooks[] = 'woocommerce_email_' . $email_placement;
}
}
$email_hooks = array_unique( apply_filters( 'wpo_wcpdf_add_document_link_to_email_hooks', $email_hooks ) );
foreach ( $email_hooks as $email_hook ) {
if ( 'woocommerce_email_customer_address_section' === $email_hook ) {
add_action( $email_hook, array( $this, 'add_document_link_to_address_section' ), 10, 4 );
} else {
add_action( $email_hook, array( $this, 'add_document_link_to_email' ), 10, 4 );
}
}
}
/**
* Wrapper for woocommerce_email_customer_address_section hook.
* Since different parameters sent to this hook, we use a wrapper for it.
*
* @param string $type
* @param \WC_Abstract_Order $order
* @param bool $sent_to_admin
* @param bool $plain_text
*
* @return void
*/
public function add_document_link_to_address_section( string $type, \WC_Abstract_Order $order, bool $sent_to_admin, bool $plain_text ): void {
// Since this hook doesn’t pass the $email object, we pass null (or create a dummy if needed).
$this->add_document_link_to_email( $order, $sent_to_admin, $plain_text, null );
}
/**
* Add document download link to the email.
*
* @param \WC_Abstract_Order $order
* @param bool $sent_to_admin
* @param bool $plain_text
* @param mixed|\WC_Email $email Some third-parties might send different values.
*
* @return void
*/
public function add_document_link_to_email( \WC_Abstract_Order $order, bool $sent_to_admin, bool $plain_text, $email ): void {
// Check if document access type is 'full'.
$is_full_access_type = 'full' === WPO_WCPDF()->endpoint->get_document_link_access_type();
// Early exit if the requirements are not met
if ( ! apply_filters( 'wpo_wcpdf_add_document_link_to_email_requirements_met', $is_full_access_type, $order, $sent_to_admin, $plain_text, $email ) ) {
return;
}
$allowed_document_types = apply_filters( 'wpo_wcpdf_add_document_link_to_email_allowed_document_types', array( 'invoice' ), $order, $sent_to_admin, $plain_text, $email );
$documents = WPO_WCPDF()->documents->get_documents();
foreach ( $documents as $document ) {
$document_settings = WPO_WCPDF()->settings->get_document_settings( $document->get_type(), 'pdf' );
$selected_emails = $document_settings['include_email_link'] ?? array();
$email_placement = $document_settings['include_email_link_placement'] ?? '';
// Skip if no email placement is set.
if ( empty( $email_placement ) ) {
continue;
}
$email_id = ( $email instanceof \WC_Email ) ? $email->id : '';
$is_allowed =
in_array( $document->get_type(), $allowed_document_types, true ) &&
in_array( $email_id, $selected_emails, true ) &&
( 'woocommerce_email_' . $email_placement ) === current_filter();
if ( ! apply_filters( 'wpo_wcpdf_add_document_link_to_email_is_allowed', $is_allowed, $order, $sent_to_admin, $plain_text, $email ) ) {
continue;
}
$document = wcpdf_get_document( $document->get_type(), $order );
if ( ! $document ) {
continue;
}
if (
! $document->exists() &&
apply_filters( 'wpo_wcpdf_add_document_link_to_email_skip_missing_documents', false, $document, $order, $sent_to_admin, $plain_text, $email )
) {
continue;
}
$link_text = sprintf(
/* translators: %s: Document type */
__( 'View %s (PDF)', 'woocommerce-pdf-invoices-packing-slips' ),
wp_kses_post( $document->get_type() )
);
$link_url = WPO_WCPDF()->endpoint->get_document_link( $order, $document->get_type(), array(), true );
$document_link = sprintf(
'%s
',
esc_attr( 'wpo_wcpdf_' . $document->get_type() . '_document_link' ),
esc_url( $link_url ),
esc_html( $link_text )
);
echo wp_kses_post( apply_filters( 'wpo_wcpdf_add_document_download_link_to_email', $document_link, $document, $order, $sent_to_admin, $plain_text, $email ) );
}
}
/**
* Apply ink-saving styles to supported templates when the feature is enabled.
*
* @param string $css
* @param OrderDocument $document
* @return string
*/
public function apply_ink_saving_styles( string $css, OrderDocument $document ): string {
$settings = WPO_WCPDF()->settings->general_settings ?? array();
$ink_saving_enabled = ! empty( $settings['template_ink_saving'] );
$current_template = $settings['template_path'] ?? '';
$supported_templates = apply_filters(
'wpo_ips_ink_saving_supported_templates',
array( 'default/Simple' )
);
// Bail if feature is disabled or template not supported.
if ( ! $ink_saving_enabled || ! in_array( $current_template, $supported_templates, true ) ) {
return $css;
}
// Let templates provide their own ink-saving CSS.
$ink_saving_css = apply_filters(
'wpo_ips_ink_saving_css',
'',
$document,
$current_template
);
if ( ! empty( trim( $ink_saving_css ) ) ) {
$css .= "\n\n" . $ink_saving_css . "\n";
}
return $css;
}
/**
* Apply template color styles to supported templates when a color is set.
*
* @param string $css
* @param object $document
* @return string
*/
public function apply_template_color_styles( string $css, $document ): string {
$settings = WPO_WCPDF()->settings->general_settings ?? array();
$template_color = $settings['template_color'] ?? '';
$current_template = $settings['template_path'] ?? '';
$supported_templates = apply_filters(
'wpo_ips_template_color_supported_templates',
array()
);
// Bail if template not supported.
if ( ! in_array( $current_template, $supported_templates, true ) ) {
return $css;
}
$defaults_map = apply_filters( 'wpo_ips_template_color_defaults_map', array() );
$default_color = $defaults_map[ $current_template ] ?? '';
// Bail if no color set, or it matches the template's own default (not a user customization).
if ( empty( $template_color ) || $template_color === $default_color ) {
return $css;
}
$css = apply_filters(
'wpo_ips_template_color_css',
$css,
$document,
$current_template,
$template_color
);
return $css;
}
}
endif; // class_exists
Galaxy S24 Plus - SchnappFix
Skip to navigation
Skip to content
Alle 10 Ergebnisse werden angezeigt
Alle 10 Ergebnisse werden angezeigt
Express Versand in der ganzen Schweiz 🇨🇭Schnelle Lieferung mit A-Post Plus – Zustellung am nächsten Werktag bei Bestellung bis 18:00 Uhr.
100 % Sicherer Checkout Bezahle bequem mit Twint, Apple Pay oder Karte.
Original- & Premium-Ersatzteile Hochwertige, geprüfte Komponenten. SchnappFix steht für Qualität und Vertrauen.
14 Tage Rückgaberecht Einfache Rückgabe innerhalb von 14 Tagen – transparent und unkompliziert
WordPress Cookie Hinweis von Real Cookie Banner
Die Zahlung war nicht erfolgreich, bitte versuchen Sie eine andere Zahlungsmethode.
SchnappFix
Diesen Code in der TWINT App eingeben:
Diesen QR-Code mit der TWINT App scannen, um den Bestellvorgang abzuschliessen.