- WordPress core y plugins - Tema Twenty Twenty-Four configurado - Plugin allow-unfiltered-html.php simplificado - .gitignore configurado para excluir wp-config.php y uploads 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1471 lines
55 KiB
PHP
Executable File
1471 lines
55 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Admin related functions
|
|
*/
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
if ( ! class_exists( 'WooFunnels_DB_Updater' ) ) {
|
|
/**
|
|
* Class WooFunnels_DB_Updater
|
|
*
|
|
*/
|
|
#[AllowDynamicProperties]
|
|
class WooFunnels_DB_Updater {
|
|
/**
|
|
* @var $ins
|
|
*/
|
|
public static $ins;
|
|
/**
|
|
* @var null Used when order indexing is running
|
|
*/
|
|
public static $indexing = null;
|
|
/**
|
|
* @var WooFunnels_Background_Updater $updater
|
|
*/
|
|
public $updater;
|
|
/**
|
|
* @var WooFunnels_Contacts_Background_Updater $contacts_updater
|
|
*/
|
|
public $contacts_updater;
|
|
/**
|
|
* @var WooFunnels_Background_Updater $updater
|
|
*/
|
|
public $order_id_in_process;
|
|
public $contact_wp_user_address_fields = array(
|
|
'address-1' => 'billing_address_1',
|
|
'address-2' => 'billing_address_2',
|
|
'city' => 'billing_city',
|
|
'state' => 'billing_state',
|
|
'postcode' => 'billing_postcode',
|
|
'country' => 'billing_country',
|
|
);
|
|
private $_user_address_meta_updated = array();
|
|
|
|
public $order_status_change = [];
|
|
|
|
/**
|
|
* WooFunnels_DB_Updater constructor.
|
|
*/
|
|
public function __construct() {
|
|
|
|
/** Showing notice to admin to allow upgrading tokens */
|
|
add_action( 'admin_notices', array( $this, 'woofunnels_show_contact_processing_notice' ) );
|
|
|
|
add_action( 'admin_init', array( $this, 'woofunnels_handle_db_upgrade_actions' ), 100 );
|
|
|
|
/** Initiate Background Database tables customer and customer on clicking 'Allow' button from tools */
|
|
add_action( 'init', array( $this, 'woofunnels_init_background_updater' ), 110 );
|
|
add_action( 'init', array( $this, 'woofunnels_init_background_contacts_updater' ), 110 );
|
|
add_action( 'admin_init', array( $this, 'woofunnels_maybe_update_customer_database' ), 120 );
|
|
|
|
/** Creating contact for new orders */
|
|
add_action( 'woocommerce_checkout_order_processed', array( $this, 'woofunnels_wc_order_create_contact' ), 10, 3 );
|
|
add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'wc_order_create_contact_blocks' ) );
|
|
|
|
/** Creating updating customer on order statuses paid */
|
|
add_action( 'woocommerce_order_status_changed', array( $this, 'order_status_change_async_call' ), 10, 3 );
|
|
|
|
/** Updating customer and customer meta on accepting offer */
|
|
add_action( 'wfocu_offer_accepted_and_processed', array( $this, 'woofunnels_offer_accept_create_update_customer' ), 1, 4 );
|
|
|
|
/** Attempt to update customer on WP profile update*/
|
|
add_action( 'profile_update', array( $this, 'bwf_update_contact_on_user_update' ), 10, 2 );
|
|
add_action( 'woocommerce_save_account_details', array( $this, 'bwf_update_contact_on_user_update' ), 10, 1 );
|
|
|
|
add_action( 'updated_user_meta', array( $this, 'mark_updated_address_fields' ), 10, 4 );
|
|
|
|
add_action( 'bwf_order_index_completed', [ $this, 'maybe_change_state_on_success' ] );
|
|
|
|
add_action( 'woocommerce_refund_created', [ $this, 'bwf_update_refunded_amount' ], 10, 2 );
|
|
|
|
add_action( 'woocommerce_before_delete_order', [ $this, 'schedule_order_reindex_action' ] );
|
|
|
|
add_action( 'rest_api_init', [ $this, 'rest_init_register_async_request' ] );
|
|
|
|
add_action( 'woofunnels_tools_add_tables_row_start', [ $this, 'bwf_add_indexing_consent_button' ], 10, 1 );
|
|
|
|
add_action( 'shutdown', [ $this, 'maybe_clean_indexing' ] );
|
|
|
|
add_action( 'admin_footer', [ $this, 'maybe_re_dispatch_background_process' ] );
|
|
|
|
add_action( 'bwf_reindex_contact_orders', [ $this, 'bwf_reindex_contact_orders' ] );
|
|
add_action( 'bwf_reindex_contact_orders_end', [ $this, 'bwf_reindex_contact_orders_end' ] );
|
|
|
|
add_action( 'init', array( $this, 'maybe_create_db_tables' ) );
|
|
|
|
add_action( 'woocommerce_order_status_changed', array( $this, 'bwf_update_cancel_order' ), 10, 3 );
|
|
}
|
|
|
|
/**
|
|
* @return WooFunnels_DB_Updater
|
|
*/
|
|
public static function get_instance() {
|
|
if ( null === self::$ins ) {
|
|
self::$ins = new self;
|
|
}
|
|
|
|
return self::$ins;
|
|
}
|
|
|
|
/**
|
|
* Creating/updating contacts and customers on offer accepted
|
|
* @SuppressWarnings(PHPMD.DevelopmentCodeFragment)
|
|
*/
|
|
public static function capture_offer_accepted_event( $request ) {
|
|
$posted_data = $request->get_body_params();
|
|
$order_id = isset( $posted_data['order_id'] ) ? $posted_data['order_id'] : 0;
|
|
$products = ( isset( $posted_data['products'] ) && count( $posted_data['products'] ) > 0 ) ? $posted_data['products'] : array();
|
|
$total = isset( $posted_data['total'] ) ? $posted_data['total'] : 0;
|
|
|
|
try {
|
|
bwf_create_update_contact( $order_id, $products, $total, false );
|
|
} catch ( Error $r ) {
|
|
BWF_Logger::get_instance()->log( print_R( $r->getMessage(), true ), 'woofunnels_indexing' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
}
|
|
}
|
|
|
|
/**
|
|
* WC order status change async call callback
|
|
*
|
|
* @param $request
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function capture_order_status_change_event( $request ) {
|
|
self::nocache_headers();
|
|
$posted_data = $request->get_body_params();
|
|
self::process_events( $posted_data );
|
|
}
|
|
|
|
public static function process_events( $posted_data ) {
|
|
|
|
if ( empty( $posted_data ) ) {
|
|
return;
|
|
}
|
|
$ins = WooFunnels_DB_Updater::get_instance();
|
|
$ins->event_advanced_logs( "Order status change endpoint data received" );
|
|
$ins->event_advanced_logs( $posted_data );
|
|
|
|
$order_id = isset( $posted_data['order_id'] ) ? $posted_data['order_id'] : 0;
|
|
$status_from = isset( $posted_data['from'] ) ? $posted_data['from'] : '';
|
|
$status_to = isset( $posted_data['to'] ) ? $posted_data['to'] : '';
|
|
|
|
/** If data not passed */
|
|
if ( empty( $order_id ) || empty( $status_from ) || empty( $status_to ) ) {
|
|
return;
|
|
}
|
|
|
|
/** If order is not valid */
|
|
$order = wc_get_order( $order_id );
|
|
if ( ! $order instanceof WC_Order ) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$paid_status = $order->has_status( wc_get_is_paid_statuses() );
|
|
if ( false === $paid_status ) {
|
|
do_action( 'fk_order_status_change_async_capture', $posted_data );
|
|
|
|
return;
|
|
}
|
|
$temp_cid = BWF_WC_Compatibility::get_order_meta( $order, '_woofunnel_custid' );
|
|
if ( empty( $temp_cid ) ) {
|
|
/** Update customer when order is paid and not indexed */
|
|
bwf_create_update_contact( $order_id, array(), 0, true );
|
|
}
|
|
do_action( 'fk_order_status_change_async_capture', $posted_data );
|
|
} catch ( Error $r ) {
|
|
$ins->event_advanced_logs( "Error occurred: " . $r->getMessage() );
|
|
}
|
|
}
|
|
|
|
public function needs_upgrade() {
|
|
return apply_filters( 'bwf_init_db_upgrade', false );
|
|
}
|
|
|
|
/**
|
|
* Set headers to prevent caching
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function nocache_headers() {
|
|
if ( headers_sent() ) {
|
|
return;
|
|
}
|
|
|
|
header( 'Cache-Control: no-cache, no-store, must-revalidate, max-age=0' );
|
|
header( 'Pragma: no-cache' );
|
|
header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
|
|
header( 'Last-Modified: false' );
|
|
}
|
|
|
|
public function woofunnels_handle_db_upgrade_actions() {
|
|
if ( isset( $_GET['_bwf_remove_updated_db_notice'] ) && isset( $_GET['_bwf_updated_nonce'] ) ) {
|
|
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_bwf_updated_nonce'] ) ), '_bwf_hide_updated_nonce' ) ) {
|
|
wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
wp_die( esc_html__( 'You don’t have permission to do this.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
$hide_notice = sanitize_text_field( wp_unslash( $_GET['_bwf_remove_updated_db_notice'] ) );
|
|
|
|
if ( 'yes' === $hide_notice ) {
|
|
$this->set_upgrade_state( '5' );
|
|
}
|
|
}
|
|
|
|
if ( isset( $_GET['bwf_update_db'] ) && isset( $_GET['_bwf_update_nonce'] ) ) {
|
|
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_bwf_update_nonce'] ) ), '_bwf_start_update_nonce' ) ) {
|
|
wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
wp_die( esc_html__( 'You don’t have permission to do this.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
$update_db = sanitize_text_field( wp_unslash( $_GET['bwf_update_db'] ) );
|
|
|
|
if ( 'yes' === $update_db && '0' === $this->get_upgrade_state() ) {
|
|
$this->set_upgrade_state( '2' );
|
|
}
|
|
}
|
|
|
|
if ( isset( $_GET['_bwf_remove_declined_notice'] ) && isset( $_GET['_bwf_declined_nonce'] ) ) {
|
|
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_bwf_declined_nonce'] ) ), '_bwf_hide_declined_nonce' ) ) {
|
|
wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
wp_die( esc_html__( 'You don’t have permission to do this.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
$hide_notice = sanitize_text_field( wp_unslash( $_GET['_bwf_remove_declined_notice'] ) );
|
|
|
|
if ( 'yes' === $hide_notice ) {
|
|
$this->set_upgrade_state( '6' );
|
|
}
|
|
}
|
|
}
|
|
|
|
public function set_upgrade_state( $stage ) {
|
|
update_option( '_bwf_db_upgrade', $stage, true );
|
|
}
|
|
|
|
public function get_upgrade_state() {
|
|
|
|
/**
|
|
* 0: upgrade is allowed, optin message should show
|
|
* 1: Upgrade is declined.
|
|
* 2: Upgrade is accepted but not dispatched
|
|
* 3: Upgrade is accepted & dispatched (show notice)
|
|
* 4: Upgrade is completed (show notice)
|
|
* 5: Upgrade is completed and notice dismissed
|
|
* 6: Upgrade is declined and dismissed
|
|
*/
|
|
return get_option( '_bwf_db_upgrade', '0' );
|
|
}
|
|
|
|
/**
|
|
* Contact processing notice to notify admin about the state
|
|
*/
|
|
public function woofunnels_show_contact_processing_notice() {
|
|
|
|
$db_state = $this->get_upgrade_state();
|
|
|
|
if ( '3' === $db_state ) { ?>
|
|
<div class="bwf-notice notice notice-success">
|
|
<div class="bwf-logo-wrapper">
|
|
<img src="<?php echo esc_url( plugin_dir_url( dirname( __FILE__ ) ) ) . 'assets/img/bwf-icon-white-bg.svg'; ?>" width="60" height="40">
|
|
</div>
|
|
|
|
<div class="bwf-message-content">
|
|
<strong><?php esc_html_e( 'Indexing of orders has started', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></strong>
|
|
<p><?php esc_html_e( 'It may take sometime to finish the process. We will update this notice once the process completes.', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
} elseif ( '4' === $db_state ) {
|
|
?>
|
|
<div class="bwf-notice notice notice-success">
|
|
<div class="bwf-logo-wrapper">
|
|
<img src="<?php echo esc_url( plugin_dir_url( dirname( __FILE__ ) ) ) . 'assets/img/bwf-icon-white-bg.svg'; ?>" width="60" height="40">
|
|
</div>
|
|
|
|
<div class="bwf-message-content">
|
|
<strong><?php esc_html_e( 'Success', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></strong>
|
|
<p><?php esc_html_e( 'Order indexing completed successfully.', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></p>
|
|
</div>
|
|
|
|
<div class="bwf-message-action">
|
|
<a class="button-secondary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( '_bwf_remove_updated_db_notice', 'yes' ), '_bwf_hide_updated_nonce', '_bwf_updated_nonce' ) ); ?>"><?php esc_html_e( 'Dismiss', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
} elseif ( '1' === $db_state ) {
|
|
?>
|
|
|
|
<div class="bwf-notice notice notice-error">
|
|
<div class="bwf-logo-wrapper">
|
|
<img src="<?php echo esc_url( plugin_dir_url( dirname( __FILE__ ) ) ) . 'assets/img/bwf-icon-white-bg.svg'; ?>" width="60" height="40">
|
|
</div>
|
|
|
|
<div class="bwf-message-content">
|
|
<strong><?php esc_html_e( 'FunnelKit Notice', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></strong>
|
|
<p><?php echo sprintf( wp_kses_post( __( 'Unable to complete indexing of orders. Please <a target="_blank" href="%s">contact support</a> to get the issue resolved.', 'woofunnels' ) ), esc_url( 'https://funnelkit.com/support/' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch, WordPress.WP.I18n.MissingTranslatorsComment ?></p>
|
|
</div>
|
|
|
|
<div class="bwf-message-action">
|
|
<a class="button-secondary" target="_blank" href="<?php echo esc_url( 'https://funnelkit.com/support/' ); ?>"><?php esc_html_e( 'Contact Support', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
<a class="button-secondary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( '_bwf_remove_declined_notice', 'yes' ), '_bwf_hide_declined_nonce', '_bwf_declined_nonce' ) ); ?>"><?php esc_html_e( 'Dismiss', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
?>
|
|
<style>
|
|
|
|
.wp-admin .bwf-notice.notice, .wp-admin.toplevel_page_woofunnels .bwf-notice.notice, .wp-admin.woofunnels_page_upstroke .bwf-notice.notice {
|
|
display: -webkit-box;
|
|
display: -webkit-flex;
|
|
display: -ms-flexbox;
|
|
display: flex !important;
|
|
-webkit-box-align: center;
|
|
-webkit-align-items: center;
|
|
-ms-flex-align: center;
|
|
align-items: center;
|
|
padding: 12px;
|
|
height: auto;
|
|
}
|
|
|
|
.wp-admin .bwf-message-content, .wp-admin.toplevel_page_woofunnels .bwf-message-content, .wp-admin.woofunnels_page_upstroke .bwf-message-content {
|
|
padding: 0 13px;
|
|
}
|
|
|
|
.wp-admin .bwf-message-action, .wp-admin.toplevel_page_woofunnels .bwf-message-action, .wp-admin.woofunnels_page_upstroke .bwf-message-action {
|
|
text-align: center;
|
|
display: -webkit-box;
|
|
display: -webkit-inline-flex;
|
|
display: -ms-flexbox;
|
|
display: inline;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-box-direction: normal;
|
|
-webkit-flex-direction: column;
|
|
-ms-flex-direction: column;
|
|
flex-direction: column;
|
|
margin-left: auto;
|
|
}
|
|
|
|
.wp-admin .bwf-message-content p, .wp-admin.toplevel_page_woofunnels .bwf-message-content p, .wp-admin.woofunnels_page_upstroke .bwf-message-content p {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.wp-admin .bwf-logo-wrapper, .wp-admin.toplevel_page_woofunnels .bwf-logo-wrapper, .wp-admin.woofunnels_page_upstroke .bwf-logo-wrapper {
|
|
/* height: 51px; */
|
|
}
|
|
|
|
.wp-admin .bwf-notice.notice.notice-success {
|
|
border-left-color: #1daafc;
|
|
}
|
|
</style>
|
|
<?php
|
|
}
|
|
|
|
// Register offer accepted and processed
|
|
|
|
/**
|
|
* Initiate WooFunnels_Background_Updater class
|
|
* @see woofunnels_maybe_update_customer_database()
|
|
*/
|
|
public function woofunnels_init_background_updater() {
|
|
if ( class_exists( 'WooFunnels_Background_Updater' ) ) {
|
|
$this->updater = new WooFunnels_Background_Updater();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initiate WooFunnels_Background_Updater class
|
|
* @see woofunnels_maybe_update_customer_database()
|
|
*/
|
|
public function woofunnels_init_background_contacts_updater() {
|
|
if ( class_exists( 'WooFunnels_Contacts_Background_Updater' ) ) {
|
|
$this->contacts_updater = new WooFunnels_Contacts_Background_Updater();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @hooked over `woocommerce_checkout_order_processed`
|
|
* Creating BWF contact if not exist on WC new order
|
|
* sync call
|
|
*
|
|
* @param $order_id
|
|
* @param $posted_data
|
|
* @param $order WC_Order
|
|
*/
|
|
public function woofunnels_wc_order_create_contact( $order_id, $posted_data, $order ) {
|
|
if ( apply_filters( 'bwf_woofunnel_skip_sub_order', true ) && wp_get_post_parent_id( $order_id ) ) {
|
|
$order = wc_get_order( $order->get_parent_id() );
|
|
}
|
|
|
|
$wp_id = $order->get_customer_id();
|
|
$email = $order->get_billing_email();
|
|
|
|
/** If no email then return */
|
|
if ( empty( $email ) ) {
|
|
return;
|
|
}
|
|
|
|
/** Assigning wp id 0 if not available */
|
|
if ( empty( $wp_id ) ) {
|
|
$wp_id = 0;
|
|
}
|
|
|
|
$bwf_contact = bwf_get_contact( $wp_id, $email );
|
|
|
|
/** If contact exists then directly add meta */
|
|
if ( $bwf_contact->get_id() > 0 ) {
|
|
$bwf_contact = bwf_create_update_contact_object( $bwf_contact, $order );
|
|
$bwf_contact->save();
|
|
BWF_Logger::get_instance()->log( "Order #" . $order->get_id() . ": Processed against contact ID" . $bwf_contact->get_id(), 'woofunnels_indexing' );
|
|
|
|
/** Save uid as cookie */
|
|
if ( ! empty( $bwf_contact->get_uid() ) && ! headers_sent() ) {
|
|
setcookie( '_fk_contact_uid', $bwf_contact->get_uid(), time() + ( 10 * YEAR_IN_SECONDS ), ( COOKIEPATH ? COOKIEPATH : '/' ), COOKIE_DOMAIN, is_ssl(), false );
|
|
}
|
|
|
|
$order->update_meta_data( '_woofunnel_cid', $bwf_contact->get_id() );
|
|
$order->save_meta_data();
|
|
|
|
return;
|
|
}
|
|
|
|
/** Need to create a contact */
|
|
if ( $wp_id > 0 ) {
|
|
$wp_user = get_user_by( 'id', $wp_id );
|
|
$email = ( $wp_user instanceof WP_User && ! empty( $wp_user->user_email ) ) ? $wp_user->user_email : $email;
|
|
}
|
|
/** If email is not valid */
|
|
if ( ! is_email( $email ) ) {
|
|
return;
|
|
}
|
|
$bwf_contact->set_email( $email );
|
|
|
|
$bwf_contact = bwf_create_update_contact_object( $bwf_contact, $order );
|
|
bwf_contact_maybe_update_creation_date( $bwf_contact, $order );
|
|
|
|
$bwf_contact->save();
|
|
BWF_Logger::get_instance()->log( "Order #" . $order->get_id() . ": Processed against contact ID" . $bwf_contact->get_id(), 'woofunnels_indexing' );
|
|
|
|
/** Save uid as cookie */
|
|
if ( ! empty( $bwf_contact->get_uid() ) && ! headers_sent() ) {
|
|
setcookie( '_fk_contact_uid', $bwf_contact->get_uid(), time() + ( 10 * YEAR_IN_SECONDS ), ( COOKIEPATH ? COOKIEPATH : '/' ), COOKIE_DOMAIN, is_ssl(), false );
|
|
}
|
|
|
|
$order->update_meta_data( '_woofunnel_cid', $bwf_contact->get_id() );
|
|
$order->save_meta_data();
|
|
}
|
|
|
|
/**
|
|
* Creating BWF contact on order created from Checkout Block/Store API
|
|
*
|
|
* @param $order WC_Order
|
|
*
|
|
* @return void
|
|
*/
|
|
public function wc_order_create_contact_blocks( $order ) {
|
|
if ( ! $order instanceof WC_Order ) {
|
|
return;
|
|
}
|
|
$this->woofunnels_wc_order_create_contact( $order->get_id(), [], $order );
|
|
}
|
|
|
|
/**
|
|
* Create nonce for rest request using wp_hash method which is unique for each site
|
|
*
|
|
* @param $action
|
|
*
|
|
* @return false|string
|
|
*/
|
|
public static function create_nonce( $action = '' ) {
|
|
return substr( wp_hash( $action, 'nonce' ), - 12, 10 );
|
|
}
|
|
|
|
/**
|
|
* verify nonce in rest calls
|
|
*
|
|
* @param $nonce
|
|
* @param $action
|
|
*
|
|
* @return bool
|
|
* @see validate()
|
|
*/
|
|
public static function verify_nonce( $nonce, $action ) {
|
|
$expected = self::create_nonce( $action );
|
|
|
|
if ( empty( $expected ) || empty( $nonce ) ) {
|
|
return false;
|
|
}
|
|
|
|
return ( hash_equals( $expected, $nonce ) );
|
|
}
|
|
|
|
/**
|
|
* Run on WC order status change
|
|
* Fire async call
|
|
*
|
|
* @param $order_id
|
|
* @param $from
|
|
* @param $to
|
|
*
|
|
* @return void
|
|
*/
|
|
public function order_status_change_async_call( $order_id, $from, $to ) {
|
|
/** Avoid duplicate run on a single call */
|
|
$arr = [ $order_id, $from, $to ];
|
|
if ( isset( $this->order_status_change[ md5( wp_json_encode( $arr ) ) ] ) ) {
|
|
return;
|
|
}
|
|
|
|
$this->order_status_change[ md5( wp_json_encode( $arr ) ) ] = 1;
|
|
|
|
$extra_data = apply_filters( 'fk_before_sending_order_status_change_async_request', [], $order_id, $from, $to );
|
|
|
|
/** Send async call */
|
|
$data = array(
|
|
'order_id' => $order_id,
|
|
'from' => $from,
|
|
'to' => $to,
|
|
'_nonce' => self::create_nonce( 'bwf_rest_order_status_changed' ),
|
|
'nonce_action' => 'bwf_rest_order_status_changed'
|
|
);
|
|
if ( ! empty( $extra_data ) && is_array( $extra_data ) ) {
|
|
$data = array_merge( $extra_data, $data );
|
|
}
|
|
|
|
$flag_saved_val = get_transient( 'bwfan_stop_async_call' );
|
|
if ( 1 === intval( $flag_saved_val ) ) {
|
|
$this->process_events( $data );
|
|
} else {
|
|
|
|
$url = home_url() . '/?rest_route=/woofunnel_customer/v1/order_status_changed';
|
|
$args = bwf_get_remote_rest_args( $data );
|
|
|
|
$this->event_advanced_logs( "Sending data for order status change JSON endpoint. URL: " . $url );
|
|
$this->event_advanced_logs( $data );
|
|
|
|
$start_time = microtime( true );
|
|
$response = wp_remote_post( $url, $args );
|
|
$end_time = microtime( true );
|
|
|
|
if ( ( $end_time - $start_time ) > 0.2 ) {
|
|
/** Curl took minimum 0.2 secs */
|
|
$flag_saved_val = get_transient( 'bwfan_stop_async_call' );
|
|
if ( empty( $flag_saved_val ) ) {
|
|
set_transient( 'bwfan_stop_async_call', 1, WEEK_IN_SECONDS );
|
|
}
|
|
}
|
|
|
|
|
|
$this->event_advanced_logs( "Order status change async call response" );
|
|
if ( is_wp_error( $response ) ) {
|
|
$this->event_advanced_logs( $response->get_error_message() );
|
|
} elseif ( isset( $response['body'] ) ) {
|
|
$this->event_advanced_logs( $response['body'] );
|
|
$this->event_advanced_logs( $response['response'] );
|
|
}
|
|
}
|
|
|
|
/** Reducing total_value with remaining order total (if partial earlier refund made) */
|
|
if ( 'cancelled' === $to ) {
|
|
BWF_Logger::get_instance()->log( "Order status changes from $from to $to for order id: $order_id", 'woofunnels_indexing' );
|
|
bwf_reduce_customer_total_on_cancel( $order_id );
|
|
}
|
|
}
|
|
|
|
public function event_advanced_logs( $log ) {
|
|
if ( empty( $log ) || false === $this->event_cb_advanced_log_enabled() ) {
|
|
return;
|
|
}
|
|
$log = array(
|
|
't' => microtime( true ),
|
|
'm' => $log,
|
|
);
|
|
|
|
add_filter( 'bwf_logs_allowed', array( $this, 'overriding_bwf_logging' ), 99999 );
|
|
BWF_Logger::get_instance()->log( print_r( $log, true ), 'fka-event-endpoint-check', 'autonami' );
|
|
remove_filter( 'bwf_logs_allowed', array( $this, 'overriding_bwf_logging' ), 99999 );
|
|
}
|
|
|
|
public function event_cb_advanced_log_enabled() {
|
|
if ( defined( 'BWFAN_ALLOW_EVENT_ENDPOINT_LOGS' ) && true === BWFAN_ALLOW_EVENT_ENDPOINT_LOGS ) {
|
|
return true;
|
|
}
|
|
if ( true === apply_filters( 'bwfan_allow_event_endpoint_logs', false ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function overriding_bwf_logging() {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Register endpoints
|
|
*
|
|
* @return void
|
|
*/
|
|
public function rest_init_register_async_request() {
|
|
//Posting data to async request for processing package product and total for indexing
|
|
register_rest_route( 'woofunnel_customer/v1', '/offer_accepted', array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( __CLASS__, 'capture_offer_accepted_event' ),
|
|
'permission_callback' => array( __CLASS__, 'validate' ),
|
|
) );
|
|
|
|
/** Posting data to async request for processing new order product on order status change */
|
|
register_rest_route( 'woofunnel_customer/v1', '/order_status_changed', array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( __CLASS__, 'capture_order_status_change_event' ),
|
|
'permission_callback' => array( __CLASS__, 'validate' ),
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* Method to validate nonce for the public creatable post requests
|
|
*
|
|
* @param WP_REST_Request $request
|
|
*
|
|
* @return false|int
|
|
*/
|
|
public static function validate( $request ) {
|
|
$posted_data = $request->get_body_params();
|
|
|
|
return self::verify_nonce( $posted_data['_nonce'], $posted_data['nonce_action'] );
|
|
}
|
|
|
|
/**
|
|
* Updating contact and customer on accepting offer
|
|
*
|
|
* @param $get_offer_id
|
|
* @param $get_package
|
|
* @param $get_parent_order
|
|
* @param $new_order
|
|
*/
|
|
public function woofunnels_offer_accept_create_update_customer( $get_offer_id, $get_package, $get_parent_order, $new_order ) {
|
|
if ( ! $get_parent_order instanceof WC_Order ) {
|
|
return;
|
|
}
|
|
|
|
$order_id = $get_parent_order->get_id();
|
|
$new_order_id = ( $new_order instanceof WC_Order ) ? $new_order->get_id() : 0;
|
|
$custid = BWF_WC_Compatibility::get_order_meta( $get_parent_order, '_woofunnel_custid' );
|
|
|
|
/**
|
|
* Updating contact and customer in async REST API request if parent order is already indexed otherwise customer will be updated during parent order status change
|
|
* If batching is off then customer will be updated during child order status change
|
|
*/
|
|
if ( $order_id && ! empty( $custid ) && empty( $new_order_id ) ) {
|
|
BWF_Logger::get_instance()->log( "Creating/Updating contact and customer in async request for batching order_id: $order_id and offer id: $get_offer_id ", 'woofunnels_indexing' );
|
|
$product_ids = array();
|
|
if ( is_array( $get_package ) && isset( $get_package['products'] ) && is_array( $get_package['products'] ) ) {
|
|
|
|
foreach ( $get_package['products'] as $product_data ) {
|
|
if ( isset( $product_data['id'] ) ) {
|
|
array_push( $product_ids, $product_data['id'] );
|
|
}
|
|
if ( isset( $product_data['_offer_data'] ) && isset( $product_data['_offer_data']->id ) && isset( $product_data['id'] ) && $product_data['id'] !== $product_data['_offer_data']->id ) {
|
|
array_push( $product_ids, $product_data['_offer_data']->id );
|
|
}
|
|
}
|
|
}
|
|
|
|
$total = isset( $get_package['total'] ) ? $get_package['total'] : 0;
|
|
$product_ids = array_unique( $product_ids );
|
|
|
|
$data = array(
|
|
'products' => $product_ids,
|
|
'total' => $total,
|
|
'order_id' => $order_id,
|
|
'_nonce' => self::create_nonce( 'bwf_rest_offer_accepted' ),
|
|
'nonce_action' => 'bwf_rest_offer_accepted'
|
|
);
|
|
$url = home_url() . '/?rest_route=/woofunnel_customer/v1/offer_accepted';
|
|
$args = bwf_get_remote_rest_args( $data );
|
|
|
|
wp_remote_post( $url, $args );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updating refunded amount in order meta
|
|
*
|
|
* @param $refund_id
|
|
* @param $args
|
|
*
|
|
* @return void
|
|
*/
|
|
public function bwf_update_refunded_amount( $refund_id, $args ) {
|
|
$order_id = isset( $args['order_id'] ) ? $args['order_id'] : 0;
|
|
$amount = isset( $args['amount'] ) ? $args['amount'] : 0;
|
|
|
|
$order = wc_get_order( $order_id );
|
|
|
|
/** only update refund in case of partial refund otherwise run the scheduler to reindex customer orders */
|
|
if ( floatval( $order->get_remaining_refund_amount() ) > 0 ) {
|
|
bwf_update_customer_refunded( $order_id, $amount );
|
|
|
|
return;
|
|
}
|
|
|
|
$this->schedule_order_reindex_action( $order_id );
|
|
}
|
|
|
|
/**
|
|
* Schedule order reindex AS action
|
|
*
|
|
* @param $id
|
|
*
|
|
* @return void
|
|
*/
|
|
public function schedule_order_reindex_action( $id = '' ) {
|
|
if ( empty( $id ) || ! class_exists( 'WooCommerce' ) || ! function_exists( 'as_has_scheduled_action' ) ) {
|
|
return;
|
|
}
|
|
|
|
/** Return if no order object */
|
|
$order = wc_get_order( $id );
|
|
if ( ! $order instanceof WC_Order ) {
|
|
return;
|
|
}
|
|
|
|
$cid = BWF_WC_Compatibility::get_order_meta( $order, '_woofunnel_cid' );
|
|
if ( empty( $cid ) ) {
|
|
return;
|
|
}
|
|
|
|
$args = [ 'cid' => $cid ];
|
|
$hook = 'bwf_reindex_contact_orders';
|
|
if ( ! as_has_scheduled_action( $hook, $args, 'funnelkit' ) ) {
|
|
as_schedule_recurring_action( time(), 60, $hook, $args, 'funnelkit' );
|
|
}
|
|
}
|
|
|
|
|
|
public function maybe_change_state_on_success() {
|
|
delete_option( '_bwf_last_offsets' );
|
|
$this->set_upgrade_state( '4' );
|
|
}
|
|
|
|
/**
|
|
* Adding allow button for db upgrade inside tools
|
|
* @SuppressWarnings(PHPMD.ElseExpression)
|
|
*/
|
|
public function bwf_add_indexing_consent_button() {
|
|
$get_threshold_order = get_option( '_bwf_order_threshold', BWF_THRESHOLD_ORDERS );
|
|
$bwf_db_upgrade = $this->get_upgrade_state();
|
|
global $wpdb;
|
|
if ( ! class_exists( 'WooCommerce' ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( '3' !== $bwf_db_upgrade || $get_threshold_order < 1 ) {
|
|
|
|
$paid_statuses = implode( ',', array_map( function ( $status ) {
|
|
return "'wc-$status'";
|
|
}, wc_get_is_paid_statuses() ) );
|
|
|
|
|
|
if ( ! BWF_WC_Compatibility::is_hpos_enabled() ) {
|
|
|
|
$query = $wpdb->prepare( "SELECT COUNT(p.ID) FROM {$wpdb->posts} AS p LEFT JOIN {$wpdb->postmeta} AS pm ON ( p.ID = pm.post_id AND pm.meta_key = '_woofunnel_cid') LEFT JOIN {$wpdb->postmeta} AS pm2 ON (p.ID = pm2.post_id) WHERE 1=1 AND pm.post_id IS NULL AND ( pm2.meta_key = '_billing_email' AND pm2.meta_value != '' ) AND p.post_type = %s AND p.post_status IN ({$paid_statuses})
|
|
ORDER BY p.post_date DESC", 'shop_order' );
|
|
|
|
} else {
|
|
$order_table = $wpdb->prefix . 'wc_orders';
|
|
$order_meta_table = $wpdb->prefix . 'wc_orders_meta';
|
|
$query = $wpdb->prepare( "SELECT COUNT(p.id) FROM {$order_table} AS p LEFT JOIN {$order_meta_table} AS pm ON ( p.id = pm.order_id AND pm.meta_key = '_woofunnel_cid') WHERE 1=1 AND pm.order_id IS NULL AND p.billing_email != '' AND
|
|
p.type = %s AND p.status IN ({$paid_statuses})
|
|
ORDER BY p.date_created_gmt DESC", 'shop_order' );
|
|
|
|
|
|
}
|
|
|
|
|
|
$query_results = $wpdb->get_var( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
$get_threshold_order = $query_results;
|
|
}
|
|
$remaining_text = '';
|
|
|
|
if ( 0 === $get_threshold_order && 0 === absint( $bwf_db_upgrade ) ) {
|
|
$this->set_upgrade_state( '5' );
|
|
$bwf_db_upgrade = '5';
|
|
}
|
|
if ( '5' !== $bwf_db_upgrade && '4' !== $bwf_db_upgrade && $get_threshold_order > 0 ) {
|
|
$remaining_text = sprintf( __( 'This store has <strong>%s orders</strong> to index.', 'woofunnels' ), $get_threshold_order ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch, WordPress.WP.I18n.MissingTranslatorsComment
|
|
}
|
|
|
|
if ( true === apply_filters( 'bwf_needs_order_indexing', false ) ) {
|
|
?>
|
|
<tr>
|
|
<th>
|
|
<strong class="name"><?php esc_html_e( 'Index Past Orders', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></strong>
|
|
<p class="description"><?php echo wp_kses_post( sprintf( 'This tool will scan all the previous orders and create an optimized index to run efficient queries. %s', $remaining_text ), 'woofunnels' ); ?></p>
|
|
<?php if ( '1' === $bwf_db_upgrade || '6' === $bwf_db_upgrade ) { ?>
|
|
<span style="width:100%; color: red;"><?php esc_html_e( 'Unable to complete indexing of orders.', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></span><br/>
|
|
<?php esc_html_e( 'Please', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?>
|
|
<a target="_blank" href="<?php echo esc_url( 'https://funnelkit.com/support/' ); ?>"><?php esc_html_e( 'contact support', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a><?php esc_html_e( ' to get the issue resolved.', 'woofunnels' ); ?>
|
|
<br/><br/>
|
|
<?php } ?>
|
|
<a href="https://funnelkit.com/docs/upstroke/miscellaneous/index-past-order/"><?php esc_html_e( 'Learn more about this process', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
</th>
|
|
<td class="run-tool">
|
|
<?php if ( '3' === $bwf_db_upgrade ) { ?>
|
|
<a href="javascript:void(0);" class="button button-large disabled"><?php esc_html_e( 'Running', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
<?php } elseif ( '4' === $bwf_db_upgrade || '5' === $bwf_db_upgrade ) { ?>
|
|
<a href="javascript:void(0);" class="button button-large disabled"><?php esc_html_e( 'Completed', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
|
|
<?php } elseif ( '1' === $bwf_db_upgrade || '6' === $bwf_db_upgrade ) { ?>
|
|
<a href="javascript:void(0);" class="button button-large disabled"><?php esc_html_e( 'Start', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
<?php
|
|
} else {
|
|
$start_url = esc_url( wp_nonce_url( add_query_arg( 'bwf_update_db', 'yes' ), '_bwf_start_update_nonce', '_bwf_update_nonce' ) );
|
|
?>
|
|
<a class="button button-large <?php echo esc_attr(( $get_threshold_order > 0 ) ? '' : 'disabled'); ?>" href="<?php echo ( $get_threshold_order > 0 ) ? esc_url($start_url) : 'javascript:void(0);'; ?>"><?php esc_html_e( 'Start', 'woofunnels' ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?></a>
|
|
<?php } ?>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $user_id
|
|
* @param $old_user_data
|
|
*
|
|
* @hooked on profile_update
|
|
*/
|
|
public function bwf_update_contact_on_user_update( $user_id, $old_user_data = [] ) {
|
|
/** If disabled */
|
|
if ( defined( 'BWF_DISABLE_CONTACT_PROFILE_UPDATE' ) && 1 === intval( BWF_DISABLE_CONTACT_PROFILE_UPDATE ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( did_action( 'woocommerce_checkout_process' ) > 0 ) {
|
|
return;
|
|
}
|
|
|
|
if ( 'profile_update' === current_action() ) {
|
|
$this->do_profile_update_async_call( $user_id, $old_user_data );
|
|
|
|
return;
|
|
}
|
|
if ( 'woocommerce_save_account_details' === current_action() ) {
|
|
$this->do_profile_update_async_call( $user_id );
|
|
}
|
|
}
|
|
|
|
/** Process profile update synchronously and handle contact data changes */
|
|
public function do_profile_update_async_call( $user_id, $old_user_data = null ) {
|
|
try {
|
|
$old_user_email = '';
|
|
if ( $old_user_data instanceof WP_User && is_email( $old_user_data->user_email ) ) {
|
|
$old_user_email = $old_user_data->user_email;
|
|
}
|
|
|
|
/** Get Changed Address Fields */
|
|
$fields = array();
|
|
foreach ( $this->_user_address_meta_updated as $meta_key => $meta_value ) {
|
|
$crm_key = array_search( $meta_key, $this->contact_wp_user_address_fields, true );
|
|
if ( empty( $crm_key ) ) {
|
|
continue;
|
|
}
|
|
|
|
$fields[ $crm_key ] = $meta_value;
|
|
}
|
|
|
|
$this->process_profile_update_sync( $user_id, $old_user_email, $fields );
|
|
} catch ( \Throwable $e ) {
|
|
BWF_logger::get_instance()->log( 'Profile update sync failed: ' . $e->getMessage(), 'woofunnels_profile_update' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Processes the profile update for a user synchronously.
|
|
*
|
|
* Updates the contact record with changed address fields and other profile information.
|
|
* Applies relevant filters and saves the contact.
|
|
*
|
|
* @param int $user_id The ID of the user being updated.
|
|
* @param string $old_user_email The previous email address of the user.
|
|
* @param array $fields Array of changed address fields keyed by CRM field name.
|
|
*/
|
|
public function process_profile_update_sync( $user_id, $old_user_email = '', $fields = array() ) {
|
|
try {
|
|
/** Return if version is less than 2.0.2 */
|
|
if ( defined( 'BWFAN_PRO_VERSION' ) && ! version_compare( BWFAN_PRO_VERSION, '2.0.2', '>' ) ) {
|
|
return;
|
|
}
|
|
|
|
$contact = $this->maybe_get_contact_on_profile_update( $user_id, $old_user_email );
|
|
|
|
if ( false === $contact ) {
|
|
$this->_user_address_meta_updated = array();
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ! class_exists( 'WooCommerce' ) || empty( $fields ) ) {
|
|
$contact->save();
|
|
|
|
return;
|
|
}
|
|
|
|
$contact = apply_filters( 'bwf_before_profile_update_contact_sync', $contact, $user_id );
|
|
|
|
foreach ( $fields as $crm_key => $meta_value ) {
|
|
if ( 'state' === $crm_key ) {
|
|
$contact->set_state( $meta_value );
|
|
continue;
|
|
}
|
|
|
|
if ( 'country' === $crm_key ) {
|
|
$contact->set_country( $meta_value );
|
|
continue;
|
|
}
|
|
|
|
$contact = apply_filters( 'bwf_profile_update_contact_sync_field', $contact, $crm_key, $meta_value, $user_id );
|
|
}
|
|
|
|
$contact = apply_filters( 'bwf_after_profile_update_contact_sync', $contact, $user_id );
|
|
|
|
$contact->set_last_modified( current_time( 'mysql', 1 ) );
|
|
$contact->save();
|
|
} catch ( \Throwable $e ) {
|
|
BWF_logger::get_instance()->log( 'Profile update processing failed: ' . $e->getMessage(), 'woofunnels_profile_update' );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Get the unsaved contact with WPID and Email changes */
|
|
public function maybe_get_contact_on_profile_update( $user_id, $old_user_email = '' ) {
|
|
/** Check if Old User Data valid */
|
|
$old_email_valid = is_email( $old_user_email );
|
|
$new_user = get_user_by( 'id', $user_id );
|
|
$new_user_email = empty( $new_user->user_email ) ? get_user_meta( $user_id, 'billing_email', true ) : $new_user->user_email;
|
|
/** If both emails are not valid */
|
|
if ( ! $old_email_valid && ! is_email( $new_user_email ) ) {
|
|
return false;
|
|
}
|
|
$new_user_exists = $new_user instanceof WP_User && is_email( $new_user_email );
|
|
|
|
/** Check if email changed */
|
|
$email_changed = $old_email_valid && $new_user_exists && $new_user_email !== $old_user_email;
|
|
/** Get Contact by Old Email & ( get new_contact, if email changed ) */
|
|
if ( ! $old_email_valid ) {
|
|
$contact = new WooFunnels_Contact( $user_id, $new_user_email );
|
|
$new_contact = null;
|
|
} else {
|
|
$contact = new WooFunnels_Contact( $user_id, $old_user_email );
|
|
$new_contact = $email_changed ? new WooFunnels_Contact( '', $new_user_email ) : null;
|
|
}
|
|
|
|
$old_contact_exists = $contact instanceof WooFunnels_Contact && absint( $contact->get_id() ) > 0;
|
|
$new_contact_exists = $new_contact instanceof WooFunnels_Contact && absint( $new_contact->get_id() ) > 0;
|
|
|
|
if ( $new_contact_exists ) {
|
|
$this->maybe_set_wpid_of_correct_contact( $new_contact, $contact, $user_id );
|
|
|
|
/** If both old and new exists, then return */
|
|
if ( $old_contact_exists ) {
|
|
return false;
|
|
}
|
|
|
|
/** If both old doesn't exists, then use new as old and go ahead */
|
|
$contact = $new_contact;
|
|
$new_contact_exists = false;
|
|
$old_contact_exists = true;
|
|
}
|
|
|
|
/** If both old and new doesn't exists, then create the contact with new email */
|
|
if ( ! $old_contact_exists && ! $new_contact_exists ) {
|
|
/** If Email changes, then contact with new email, else old one */
|
|
$contact = $new_contact instanceof WooFunnels_Contact ? $new_contact : $contact;
|
|
|
|
/** If contact is not WooFunnels_Contact */
|
|
$contact = $contact instanceof WooFunnels_Contact ? $contact : new WooFunnels_Contact( $user_id, $new_user->user_email );
|
|
$old_contact_exists = true;
|
|
}
|
|
|
|
if ( $new_user_exists ) {
|
|
$contact->set_f_name( $new_user->first_name );
|
|
$contact->set_l_name( $new_user->last_name );
|
|
}
|
|
|
|
/** Update WPID if old WPID is different */
|
|
if ( $user_id !== absint( $contact->get_wpid() ) ) {
|
|
$contact->set_wpid( $user_id );
|
|
}
|
|
|
|
/** Update email if changed */
|
|
if ( $new_user_exists && $email_changed ) {
|
|
$contact->set_email( $new_user->user_email );
|
|
}
|
|
|
|
return $contact;
|
|
}
|
|
|
|
private function maybe_set_wpid_of_correct_contact( $new_contact, $old_contact, $user_id ) {
|
|
global $wpdb;
|
|
|
|
$old_contact_exists = $old_contact instanceof WooFunnels_Contact && absint( $old_contact->get_id() ) > 0;
|
|
$new_contact_exists = $new_contact instanceof WooFunnels_Contact && absint( $new_contact->get_id() ) > 0;
|
|
|
|
/** Set wpid, if not same */
|
|
if ( $new_contact_exists && $user_id !== absint( $new_contact->get_wpid() ) ) {
|
|
$new_contact->set_wpid( $user_id );
|
|
$new_contact->set_last_modified( current_time( 'mysql', 1 ) );
|
|
$new_contact->save();
|
|
}
|
|
|
|
/** Remove WPID on old contact if same as user_id */
|
|
if ( $old_contact_exists && $user_id === absint( $old_contact->get_wpid() ) ) {
|
|
/** Using SQL because setting wpid as blank is not supported in core */
|
|
//phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
$wpdb->update( $wpdb->prefix . 'bwf_contact', array(
|
|
'wpid' => 0,
|
|
'last_modified' => current_time( 'mysql', 1 ),
|
|
), array( 'id' => $old_contact->get_id() ) );
|
|
}
|
|
}
|
|
|
|
public function mark_updated_address_fields( $meta_id, $object_id, $meta_key, $_meta_value ) {
|
|
/** Return if version is less than 2.0.2 */
|
|
if ( defined( 'BWFAN_PRO_VERSION' ) && ! version_compare( BWFAN_PRO_VERSION, '2.0.2', '>' ) ) {
|
|
return;
|
|
}
|
|
|
|
$address_meta_keys = array_values( $this->contact_wp_user_address_fields );
|
|
if ( in_array( $meta_key, $address_meta_keys, true ) ) {
|
|
$this->_user_address_meta_updated[ $meta_key ] = $_meta_value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public function maybe_clean_indexing() {
|
|
if ( 1 === did_action( 'admin_head' ) && current_user_can( 'manage_options' ) && 'yes' === filter_input( INPUT_GET, 'bwf_index_clean', FILTER_UNSAFE_RAW ) ) { //phpcs:ignore
|
|
$this->reset_indexing_data();
|
|
}
|
|
$this->bwf_maybe_restart_indexing();
|
|
}
|
|
|
|
/**
|
|
* reset and clean index data for restart index
|
|
* @return void
|
|
*/
|
|
public function reset_indexing_data() {
|
|
global $wpdb;
|
|
|
|
$tables = array(
|
|
'bwf_wc_customers',
|
|
);
|
|
|
|
foreach ( $tables as &$table ) {
|
|
$bwf_table = $wpdb->prefix . $table;
|
|
$bwf_table = esc_sql( $bwf_table ); //sanitize the table name manually
|
|
$wpdb->query( "TRUNCATE TABLE {$bwf_table}" );
|
|
}
|
|
|
|
/**
|
|
* Remove bwf_wc_customers table from table list for attempt to recreate table
|
|
*/
|
|
$current_table_list = get_option( '_bwf_db_table_list' );
|
|
|
|
if ( is_array( $current_table_list ) && isset( $current_table_list['tables'] ) && count( $current_table_list['tables'] ) > 0 ) {
|
|
$table_list = array_unique( $current_table_list['tables'] );
|
|
foreach ( $table_list as $key ) {
|
|
if ( 'bwf_wc_customers' === $key ) {
|
|
unset( $table_list[ $key ] );
|
|
$current_table_list['tables'] = array_values( $table_list );
|
|
update_option( '_bwf_db_table_list', $current_table_list, true );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
delete_option( '_bwf_db_upgrade' );
|
|
delete_option( '_bwf_order_threshold' );
|
|
delete_option( '_bwf_offset' );
|
|
delete_option( '_bwf_last_offsets' );
|
|
delete_option( '_bwf_contacts_threshold' );
|
|
delete_option( '_bwf_contacts_offset' );
|
|
delete_option( '_bwf_contacts_last_offsets' );
|
|
|
|
$table = $wpdb->prefix . 'postmeta';
|
|
$wpdb->delete( $table, array( 'meta_key' => '_woofunnel_cid' ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
|
$wpdb->delete( $table, array( 'meta_key' => '_woofunnel_custid' ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
|
if ( BWF_WC_Compatibility::is_hpos_enabled() ) {
|
|
$table = $wpdb->prefix . 'wc_orders_meta';
|
|
|
|
$wpdb->delete( $table, array( 'meta_key' => '_woofunnel_cid' ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
|
$wpdb->delete( $table, array( 'meta_key' => '_woofunnel_custid' ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
|
|
|
}
|
|
$this->updater->kill_process_safe();
|
|
BWF_Logger::get_instance()->log( 'Indexing was cleaned manually.', 'woofunnels_indexing' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
}
|
|
|
|
/**
|
|
* Restart indexing when it is stop due to any reason like cron disabled, server stopped etc
|
|
*/
|
|
public function bwf_maybe_restart_indexing() {
|
|
if ( 1 === did_action( 'admin_head' ) && current_user_can( 'manage_options' ) && 'yes' === filter_input( INPUT_GET, 'bwf_restart_indexing', FILTER_UNSAFE_RAW ) ) {
|
|
$this->set_upgrade_state( '2' );
|
|
$this->woofunnels_maybe_update_customer_database();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @hooked over `admin_head`
|
|
* This method takes care of database updating process.
|
|
* Checks whether there is a need to update the database
|
|
* Iterates over define callbacks and passes it to background updater class
|
|
* Update bwf_customer and bwf_customer_meta tables with new token from different tables
|
|
*/
|
|
public function woofunnels_maybe_update_customer_database() {
|
|
|
|
if ( is_null( $this->updater ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( isset( $_GET['bwf_update_db'] ) && isset( $_GET['_bwf_update_nonce'] ) ) {
|
|
if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_bwf_update_nonce'] ) ), '_bwf_start_update_nonce' ) ) {
|
|
wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
wp_die( esc_html__( 'You don’t have permission to do this.', 'woofunnels' ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
$bwf_update_db = sanitize_text_field( wp_unslash( $_GET['bwf_update_db'] ) );
|
|
|
|
$get_state = $this->get_upgrade_state();
|
|
if ( 'yes' === $bwf_update_db && '2' === $get_state ) {
|
|
$this->bwf_start_indexing();
|
|
}
|
|
}
|
|
}
|
|
|
|
public function bwf_start_indexing() {
|
|
$task = 'bwf_create_update_contact_customer'; //Scanning order table and updating customer tables
|
|
$this->updater->push_to_queue( $task );
|
|
BWF_Logger::get_instance()->log( '**************START INDEXING************', 'woofunnels_indexing' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
$this->set_upgrade_state( '3' );
|
|
$this->updater->save()->dispatch();
|
|
BWF_Logger::get_instance()->log( 'First Dispatch completed', 'woofunnels_indexing' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
}
|
|
|
|
public function capture_fatal_error() {
|
|
$error = error_get_last();
|
|
if ( ! empty( $error ) ) {
|
|
if ( is_array( $error ) && in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) {
|
|
|
|
if ( $this->is_ignorable_error( $error['message'] ) ) {
|
|
return;
|
|
}
|
|
BWF_Logger::get_instance()->log( 'Error logged during the process' . print_r( $error, true ), 'woofunnels_indexing' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
|
|
$current_offset = get_option( '_bwf_offset', 0 );
|
|
$current_offset ++;
|
|
update_option( '_bwf_offset', $current_offset );
|
|
|
|
$order_id = WooFunnels_Dashboard::$classes['WooFunnels_DB_Updater']->get_order_id_process();
|
|
$order = wc_get_order( $order_id );
|
|
if ( $order instanceof WC_Order ) {
|
|
|
|
$order->update_meta_data( '_woofunnel_cid', 0 );
|
|
$order->save_meta_data();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private function is_ignorable_error( $str ) {
|
|
$get_all_ingorable_regex = $this->ignorable_errors();
|
|
|
|
foreach ( $get_all_ingorable_regex as $re ) {
|
|
$matches = [];
|
|
preg_match_all( $re, $str, $matches, PREG_SET_ORDER, 0 );
|
|
if ( ! empty( $matches ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function ignorable_errors() {
|
|
return [ '/Maximum execution time of/m', '/Allowed memory size of/m' ];
|
|
}
|
|
|
|
public function capture_fatal_error_contacts() {
|
|
$error = error_get_last();
|
|
if ( ! empty( $error ) ) {
|
|
if ( is_array( $error ) && in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) {
|
|
|
|
if ( $this->is_ignorable_error( $error['message'] ) ) {
|
|
return;
|
|
}
|
|
BWF_Logger::get_instance()->log( 'Error logged during the process' . print_r( $error, true ), 'woofunnels_contacts_indexing' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
|
|
$current_offset = get_option( '_bwf_contacts_offset', 0 );
|
|
$current_offset ++;
|
|
update_option( '_bwf_contacts_offset', $current_offset );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public function set_order_id_in_process( $order_id ) {
|
|
$this->order_id_in_process = $order_id;
|
|
}
|
|
|
|
public function get_order_id_process() {
|
|
return $this->order_id_in_process;
|
|
}
|
|
|
|
public function maybe_re_dispatch_background_process() {
|
|
$this->updater->maybe_re_dispatch_background_process();
|
|
}
|
|
|
|
public function maybe_dispatch_contact_table_indexing() {
|
|
$task_list = array(
|
|
'bwf_contacts_v1_0_init_db_setup',
|
|
);
|
|
|
|
$update_queued = false;
|
|
|
|
foreach ( $task_list as $task ) {
|
|
|
|
$this->contacts_updater->push_to_queue( $task );
|
|
$update_queued = true;
|
|
}
|
|
|
|
if ( $update_queued ) {
|
|
|
|
$this->contacts_updater->save()->dispatch();
|
|
}
|
|
}
|
|
|
|
public function maybe_flag_old_contacts_indexing() {
|
|
$indexing_option = get_option( '_bwf_migrate_contacts_indexing' );
|
|
if ( ! empty( $indexing_option ) ) {
|
|
return;
|
|
}
|
|
|
|
global $wpdb;
|
|
$bwf_tables = get_option( '_bwf_created_tables' );
|
|
if ( ! is_array( $bwf_tables ) || ! in_array( $wpdb->prefix . 'bwf_contact', $bwf_tables, true ) || ! in_array( $wpdb->prefix . 'bwf_contact_meta', $bwf_tables, true ) ) {
|
|
return;
|
|
}
|
|
|
|
$contact_count = $wpdb->get_var( "SELECT COUNT(id) FROM {$wpdb->prefix}bwf_contact" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
if ( 0 === absint( $contact_count ) ) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* 1 - Pending
|
|
* 2 - In Progress
|
|
* 3 - Complete
|
|
*/
|
|
update_option( '_bwf_migrate_contacts_indexing', 1 );
|
|
}
|
|
|
|
public function maybe_create_db_tables() {
|
|
WooFunnels_Create_DB_Tables::get_instance()->create();
|
|
}
|
|
|
|
/**
|
|
* Reindex contact orders
|
|
*
|
|
* @param $cid
|
|
*
|
|
* @return mixed false || 0 : not completed || 1 : completed
|
|
*/
|
|
public function bwf_reindex_contact_orders( $cid ) {
|
|
$bwf_contact = new WooFunnels_Contact( '', '', '', $cid );
|
|
if ( 0 === $bwf_contact->get_id() ) {
|
|
$this->un_schedule_wc_recurring_actions( $cid );
|
|
|
|
return false;
|
|
}
|
|
|
|
$paid_statuses = implode( ',', array_map( function ( $status ) {
|
|
return "'wc-$status'";
|
|
}, wc_get_is_paid_statuses() ) );
|
|
|
|
$key = "bwf_contact_orders_{$cid}";
|
|
|
|
$indexed_order_id = get_option( $key, 0 );
|
|
if ( 0 > $indexed_order_id ) {
|
|
return 1;
|
|
}
|
|
global $wpdb;
|
|
|
|
/** Delete custom table row when starting from 0 i.e. initial starting for a contact */
|
|
if ( 0 === intval( $indexed_order_id ) ) {
|
|
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}bwf_wc_customers WHERE cid = %d", $cid ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL
|
|
}
|
|
|
|
$limit = 10;
|
|
try {
|
|
if ( ! BWF_WC_Compatibility::is_hpos_enabled() ) {
|
|
$sql = "SELECT p.ID FROM {$wpdb->prefix}posts AS p INNER JOIN {$wpdb->prefix}postmeta AS pm ON ( p.ID = pm.post_id ) WHERE 1=1 AND ( ( ( pm.meta_key = %s AND pm.meta_value = %s ) ) ) AND p.post_type = %s AND (p.post_status IN ($paid_statuses)) AND p.ID > %d GROUP BY p.ID ORDER BY p.ID ASC LIMIT 0, " . $limit;
|
|
$orders_ids = $wpdb->get_col( $wpdb->prepare( $sql, array( '_woofunnel_cid', $cid, 'shop_order', $indexed_order_id ) ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
} else {
|
|
$order_table = $wpdb->prefix . 'wc_orders';
|
|
$order_meta_table = $wpdb->prefix . 'wc_orders_meta';
|
|
$sql = ( "SELECT o.id FROM {$order_table} AS o INNER JOIN {$order_meta_table} AS om ON o.id = om.order_id AND om.meta_key = %s AND om.meta_value = %d WHERE o.status IN ({$paid_statuses}) AND o.type = %s AND o.id > %d ORDER BY o.id ASC LIMIT 0, " . $limit );
|
|
$orders_ids = $wpdb->get_col( $wpdb->prepare( $sql, array( '_woofunnel_cid', $cid, 'shop_order', $indexed_order_id ) ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
}
|
|
} catch ( Error|Exception $e ) {
|
|
$this->un_schedule_wc_recurring_actions( $cid );
|
|
|
|
return 1;
|
|
}
|
|
|
|
if ( empty( $orders_ids ) ) {
|
|
$this->un_schedule_wc_recurring_actions( $cid );
|
|
|
|
return 1;
|
|
}
|
|
|
|
$old_processed_oids = $bwf_contact->get_meta( 'processed_order_ids' );
|
|
$old_processed_oids = is_array( $old_processed_oids ) ? array_map( 'intval', $old_processed_oids ) : [];
|
|
$processed_oids = [];
|
|
foreach ( $orders_ids as $id ) {
|
|
if ( in_array( intval( $id ), $old_processed_oids, true ) ) {
|
|
continue;
|
|
}
|
|
|
|
$order = wc_get_order( $id );
|
|
if ( ! $order instanceof WC_Order ) {
|
|
$processed_oids[] = $id;
|
|
continue;
|
|
}
|
|
|
|
$order->delete_meta_data( '_woofunnel_cid' );
|
|
$order->delete_meta_data( '_woofunnel_custid' );
|
|
$order->save_meta_data();
|
|
|
|
bwf_create_update_contact( $id, array(), 0, true );
|
|
|
|
/** Update order id on a key index */
|
|
update_option( $key, $id, false );
|
|
$processed_oids[] = $id;
|
|
}
|
|
|
|
$processed_oids = array_unique( array_merge( $old_processed_oids, $processed_oids ) );
|
|
sort( $processed_oids );
|
|
$bwf_contact->update_meta( 'processed_order_ids', maybe_serialize( $processed_oids ) );
|
|
|
|
return count( $orders_ids ) < $limit ? 1 : 0; // return 1 or 0 if more orders or not
|
|
}
|
|
|
|
/**
|
|
* Callback to Un-schedule contact orders sync recurring action
|
|
*
|
|
* @param $cid
|
|
*
|
|
* @return void
|
|
*/
|
|
public function un_schedule_wc_recurring_actions( $cid ) {
|
|
if ( empty( $cid ) ) {
|
|
return;
|
|
}
|
|
|
|
update_option( "bwf_contact_orders_{$cid}", '-1', false );
|
|
|
|
$hook = 'bwf_reindex_contact_orders_end';
|
|
if ( ! as_has_scheduled_action( $hook, [ 'cid' => $cid ], 'funnelkit' ) ) {
|
|
as_schedule_single_action( time(), $hook, [ 'cid' => $cid ], 'funnelkit' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Un-schedule main recurring action from this single action
|
|
*
|
|
* @param $cid
|
|
*
|
|
* @return void
|
|
*/
|
|
public function bwf_reindex_contact_orders_end( $cid ) {
|
|
if ( empty( $cid ) ) {
|
|
return;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
delete_option( "bwf_contact_orders_{$cid}" );
|
|
$bwf_contact = new WooFunnels_Contact( '', '', '', $cid );
|
|
$bwf_contact->delete_meta( 'processed_order_ids' );
|
|
|
|
$hook = 'bwf_reindex_contact_orders';
|
|
$args = wp_json_encode( [ 'cid' => $cid ] );
|
|
|
|
/** query */
|
|
$query = "DELETE FROM `{$wpdb->prefix}actionscheduler_actions` WHERE `args` = %s AND `hook` = %s Limit 25";
|
|
$query = $wpdb->prepare( $query, $args, $hook );
|
|
|
|
$run = true;
|
|
do {
|
|
$deleted = $wpdb->query( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
if ( ! $deleted ) {
|
|
$run = false;
|
|
}
|
|
} while ( $run );
|
|
}
|
|
|
|
/**
|
|
* schedule to sync all the orders of contact on cancel
|
|
*
|
|
* @param $order_id
|
|
* @param $from
|
|
* @param $to
|
|
*
|
|
* @return void
|
|
*/
|
|
public function bwf_update_cancel_order( $order_id, $from, $to ) {
|
|
/** return if from status is not paid status or to status is not cancelled */
|
|
$failed_statuses = [ 'pending', 'failed', 'cancelled' ];
|
|
if ( in_array( $from, $failed_statuses, true ) || 'cancelled' !== $to ) {
|
|
return;
|
|
}
|
|
|
|
$this->schedule_order_reindex_action( $order_id );
|
|
}
|
|
|
|
/**
|
|
* Truncate the contact meta table
|
|
* Run when BWF_DB_VERSION is 1.0.3
|
|
*/
|
|
protected function empty_contact_meta_table() {
|
|
global $wpdb;
|
|
$result = $wpdb->get_results( "SHOW TABLES LIKE '{$wpdb->prefix}bwf_contact_meta'", ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
|
if ( is_array( $result ) && count( $result ) > 0 ) {
|
|
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}bwf_contact_meta`" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|