Files
roi-theme/wp-content/plugins/wp-marketing-automations-pro/crm/includes/class-bwfcrm-bulk-action-handler.php
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- 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>
2025-11-03 21:04:30 -06:00

518 lines
14 KiB
PHP
Executable File

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Class Bulk Action handler
*/
#[AllowDynamicProperties]
class BWFCRM_Bulk_Action_Handler {
/**
* Class Instance
*
* @var null
*/
private static $ins = null;
private $action_hook = 'bwfcrm_bulk_action_process';
/**
* Working Action ID
* @var int
*/
private $action_id = 0;
/**
* Working Bulk Action data
*
* @var array
*/
private $bulk_action_data = [];
private $current_pos = 0;
private $start_time = 0;
private $last_processed = 0;
private $contacts = [];
private $ended = false;
private $logs = array();
/**
* Class instance
*
* @return BWFCRM_Bulk_Action_Handler|null
*/
public static function get_instance() {
if ( null === self::$ins ) {
self::$ins = new self();
}
return self::$ins;
}
/**
* Class constructor
*/
public function __construct() {
add_action( $this->action_hook, [ $this, 'process_bulk_action' ] );
}
/**
* Process bulk action
*
* @param $id
*/
public function process_bulk_action( $id ) {
/** Fetch Bulk Action data */
$data = $this->get_row_data( $id );
/** Setting working action id */
$this->action_id = $id;
$this->current_pos = absint( $this->bulk_action_data['offset'] );
$this->last_processed = absint( $this->bulk_action_data['processed'] );
/** End action scheduler if status is not ongoing */
if ( ! $data || ( isset( $data['actions'] ) && empty( $data['actions'] ) ) ) {
$this->end_bulk_action();
return;
}
/** Open file */
$file = fopen( BWFCRM_BULK_ACTION_LOG_DIR . '/' . $this->bulk_action_data['log_file'], "a" );
/** Maybe don't run automations */
if ( ! isset( $this->bulk_action_data['enable_automation_run'] ) || false === $this->bulk_action_data['enable_automation_run'] ) {
$this->maybe_not_run_automations( $this->bulk_action_data['actions'] );
} else {
/** Validate automation basic setting to avoid checking again */
$this->maybe_filter_automations( $this->bulk_action_data['actions'] );
/** Don't run automation immediately if bulk action processed */
BWFAN_PRO_Common::disable_run_v2_automation_immediately();
}
$this->start_time = time();
$run_time = $this->get_per_call_time();
$this->set_log( 'Bulk action started' );
while ( ( ( time() - $this->start_time ) < $run_time ) && ! BWFCRM_Common::memory_exceeded() ) {
/** Populate contacts */
$this->populate_contacts();
/** Check if contacts are empty */
if ( empty( $this->contacts['contacts'] ) ) {
$this->end_bulk_action();
return;
}
/** Start execution */
$this->process( $file );
}
/** Closing file */
if ( ! empty( $file ) ) {
fclose( $file );
}
if ( $this->get_percent_completed() >= 100 ) {
$this->end_bulk_action();
}
/** Clear cached data */
$this->maybe_clear_trigger_automations();
$this->set_log( 'Bulk action execution ended' );
}
public function populate_contacts() {
/** Fetch contacts */
$additional_info = [
'order_by' => 'id',
'order' => "ASC"
];
if ( isset( $this->bulk_action_data['exclude_ids'] ) && ! empty( $this->bulk_action_data['exclude_ids'] ) ) {
$additional_info['exclude_ids'] = $this->bulk_action_data['exclude_ids'];
}
if ( isset( $this->bulk_action_data['include_ids'] ) && ! empty( $this->bulk_action_data['include_ids'] ) ) {
$additional_info['include_ids'] = $this->bulk_action_data['include_ids'];
}
$filters = [];
if ( $this->last_processed > 0 ) {
$filters['contact_id_more_than'] = $this->last_processed;
}
$filters = ! empty( $this->bulk_action_data['contactFilters'] ) ? array_merge( $this->bulk_action_data['contactFilters'], $filters ) : $filters;
$this->contacts = BWFCRM_Contact::get_contacts( '', 0, 20, $filters, $additional_info, OBJECT, true );
$this->set_log( 'Contacts fetched: ' . count( $this->contacts['contacts'] ) );
}
/**
* Schedule AS action for bulk action execution
*
* @param $id
*
* @return void
*/
public function schedule_bulk_action( $id ) {
/** Check if action is already scheduled */
if ( bwf_has_action_scheduled( $this->action_hook, array( 'bulk_action_id' => absint( $id ) ), 'bwfcrm' ) ) {
return;
}
bwf_schedule_recurring_action( time(), 60, $this->action_hook, array( 'bulk_action_id' => absint( $id ) ), 'bwfcrm' );
/** Ping worker */
BWFCRM_Common::ping_woofunnels_worker();
}
/**
* Un-schedule the action if scheduled and mark bulk action 'end'
*
* @return void
*/
public function end_bulk_action() {
if ( true === $this->ended ) {
return;
}
/** Check if action is already scheduled */
if ( bwf_has_action_scheduled( $this->action_hook, array( 'bulk_action_id' => absint( $this->action_id ) ), 'bwfcrm' ) ) {
bwf_unschedule_actions( $this->action_hook, array( 'bulk_action_id' => absint( $this->action_id ) ), 'bwfcrm' );
}
/** Change bulk action status to completed */
BWFAN_Model_Bulk_Action::update( array( 'status' => 2, 'updated_at' => current_time( 'mysql', 1 ) ), array( 'id' => absint( $this->action_id ) ) );
$this->set_log( 'Bulk action completed' );
$this->log();
$this->ended = true;
}
/**
* Get Bulk Action data by ID primary key
*
* @param $id
*
* @return array|false|mixed
*/
public function get_row_data( $id ) {
/** Check action id */
if ( empty( $id ) ) {
return false;
}
/** Fetch Bulk Action data */
$data = BWFAN_Model_Bulk_Action::bwfan_get_bulk_action( $id );
/** Setting working bulk action data */
$this->bulk_action_data = $data;
/** End action scheduler if status is not ongoing */
if ( empty( $data ) ) {
return false;
}
return $data;
}
/**
* Get Bulk Action status
*
* @param $id
*
* @return array
*/
public function get_bulk_action_status( $id = 0 ) {
/** Fetch Bulk Action data */
$data = $this->get_row_data( $id );
/** End action scheduler if status is not ongoing */
if ( ! $data ) {
$this->action_id = $id;
$this->end_bulk_action();
return [];
}
/**
* Get percent completed
*/
$percent = $this->get_percent_completed();
$status = absint( $data['status'] );
$offset = absint( $data['offset'] );
return array(
'bulk_action_id' => $id,
'percent' => $percent,
'status' => $status,
'offset' => $offset,
'log' => isset( $data['log'] ) ? $data['log'] : []
);
}
/**
* Return percentage completed
*
* @return int
*/
public function get_percent_completed() {
$count = isset( $this->bulk_action_data['count'] ) && ! empty( intval( $this->bulk_action_data['count'] ) ) ? intval( $this->bulk_action_data['count'] ) : 0;
$offset = isset( $this->bulk_action_data['offset'] ) && ! empty( intval( $this->bulk_action_data['offset'] ) ) ? intval( $this->bulk_action_data['offset'] ) : 0;
if ( 0 === $count ) {
return 100;
}
if ( 0 === $offset ) {
return 0;
}
/** In case processed count is greater than total count */
if ( $offset > $count ) {
BWFAN_Model_Bulk_Action::update( array( 'count' => $offset, 'updated_at' => current_time( 'mysql', 1 ) ), array( 'id' => absint( $this->bulk_action_data['ID'] ) ) );
return 100;
}
return absint( min( ( ( $offset / $count ) * 100 ), 100 ) );
}
/**
* Remove the already running action and Re-schedule new one,
* And ping WooFunnels worker to run immediately
*
* @param int $id
*/
public function reschedule_background_action( $id ) {
$this->action_id = $id;
/** Check if action is already scheduled and end it id exist */
$this->end_bulk_action();
/** Schedule bulk action */
$this->schedule_bulk_action( $id );
}
/**
* Process Bulk actions on contacts
*
* @param $file
*
* @return void
*/
public function process( $file ) {
$this->bulk_action_data['actions']['id'] = $this->action_id;
$count = 0;
foreach ( $this->contacts['contacts'] as $contact ) {
if ( ! $contact instanceof BWFCRM_Contact || ! $contact->is_contact_exists() ) {
continue;
}
/** Perform Actions */
$res = BWFCRM_Core()->actions->process_all_actions( $this->bulk_action_data['actions'], $contact );
$data = [ $contact->get_id() ];
foreach ( $res as $key => $value ) {
if ( ! isset( $value['status'] ) ) {
array_push( $data, 'no' );
continue;
}
switch ( intval( $value['status'] ) ) {
case 2 :
array_push( $data, 'yes' );
break;
case 3:
array_push( $data, 'skip' . ( isset( $value['message'] ) ? ' ( ' . $value['message'] . ' )' : '' ) );
break;
default:
array_push( $data, 'no' . ( isset( $value['message'] ) ? ' ( ' . $value['message'] . ' )' : '' ) );
break;
}
}
$this->set_log( 'processing single contact. ID: ' . implode( ',', $data ) );
/** Updating log file */
if ( ! empty( $file ) ) {
fputcsv( $file, $data );
}
$this->last_processed = $contact->get_id();
$count ++;
}
$this->current_pos += $count;
$this->bulk_action_data['offset'] = $this->current_pos;
$this->update_offset();
}
/**
* Update the offset and processed columns values in the DB
* @return void
*/
public function update_offset() {
$data = array( 'offset' => $this->current_pos, 'processed' => $this->last_processed, 'updated_at' => current_time( 'mysql', 1 ) );
BWFAN_Model_Bulk_Action::update( $data, array( 'id' => absint( $this->action_id ) ) );
}
/**
* Disallow automations to run, so set blank cache
*
* @param $actions
*
* @return void
*/
protected function maybe_not_run_automations( $actions ) {
if ( empty( $actions ) ) {
return;
}
$action_slugs = array_keys( $actions );
$action_slugs = array_unique( $action_slugs );
sort( $action_slugs );
/** Cache obj instance */
$WooFunnels_Cache_obj = WooFunnels_Cache::get_instance();
$ins = BWFCRM_Actions_Handler::get_instance();
foreach ( $action_slugs as $slug ) {
$bulk_action_ins = $ins->get_action_by_slug( $slug );
if ( is_null( $bulk_action_ins ) ) {
continue;
}
$event_slug = $bulk_action_ins->get_action_event_slug();
if ( empty( $event_slug ) ) {
continue;
}
$key = 'bwfan_active_automations_v2_' . $event_slug;
$WooFunnels_Cache_obj->set_cache( $key, [], 'autonami' );
$key = 'bwfan_active_automations_' . $event_slug;
$WooFunnels_Cache_obj->set_cache( $key, [], 'autonami' );
}
}
/**
* Clear cache object instance
*
* @return void
*/
protected function maybe_clear_trigger_automations() {
$WooFunnels_Cache_obj = WooFunnels_Cache::get_instance();
$WooFunnels_Cache_obj->reset_cache( 'autonami' );
}
/**
* Filter automations by checking their settings to avoid checking again
*
* @param $actions
*
* @return void
*/
protected function maybe_filter_automations( $actions ) {
if ( empty( $actions ) ) {
return;
}
$action_slugs = array_keys( $actions );
$action_slugs = array_unique( $action_slugs );
sort( $action_slugs );
/** Cache obj instance */
$WooFunnels_Cache_obj = WooFunnels_Cache::get_instance();
$ins = BWFCRM_Actions_Handler::get_instance();
foreach ( $action_slugs as $slug ) {
$bulk_action_ins = $ins->get_action_by_slug( $slug );
if ( is_null( $bulk_action_ins ) ) {
continue;
}
$event_slug = $bulk_action_ins->get_action_event_slug();
if ( empty( $event_slug ) ) {
continue;
}
$event = BWFAN_Core()->sources->get_event( $event_slug );
/** v1 checking */
$v1_automations = BWFAN_Core()->automations->get_active_automations( 1, $event_slug );
if ( ! empty( $v1_automations ) && count( $v1_automations ) > 0 ) {
$invalid_v1_automations = [];
foreach ( $v1_automations as $a_id => $automation_data ) {
$res = $event->validate_bulk_action_event_settings( $actions[ $slug ], $automation_data, 1 );
if ( false === $res ) {
$invalid_v1_automations[] = $a_id;
}
}
$key1 = 'bwfan_active_automations_' . $event_slug;
$v1_active_automations = $WooFunnels_Cache_obj->get_cache( $key1, 'autonami' );
$v1_active_automations = array_values( array_filter( $v1_active_automations, function ( $v1_a_a ) use ( $invalid_v1_automations ) {
return ! in_array( $v1_a_a['ID'], $invalid_v1_automations );
} ) );
$v1_active_automations = empty( $v1_active_automations ) ? [] : $v1_active_automations;
$WooFunnels_Cache_obj->set_cache( $key1, $v1_active_automations, 'autonami' );
}
/** v2 checking */
$v2_automations = BWFAN_Core()->automations->get_active_automations( 2, $event_slug );
if ( ! empty( $v2_automations ) && count( $v2_automations ) > 0 ) {
$invalid_v2_automations = [];
foreach ( $v2_automations as $v2_a_id => $_v2_automation_data ) {
$res = $event->validate_bulk_action_event_settings( $actions[ $slug ], $_v2_automation_data, 2 );
if ( false === $res ) {
$invalid_v2_automations[] = $v2_a_id;
}
}
$key2 = 'bwfan_active_automations_v2_' . $event_slug;
$v2_active_automations = $WooFunnels_Cache_obj->get_cache( $key2, 'autonami' );
$v2_active_automations = array_values( array_filter( $v2_active_automations, function ( $v2_a_a ) use ( $invalid_v2_automations ) {
return ! in_array( $v2_a_a['ID'], $invalid_v2_automations );
} ) );
$v2_active_automations = empty( $v2_active_automations ) ? [] : $v2_active_automations;
$WooFunnels_Cache_obj->set_cache( $key2, $v2_active_automations, 'autonami' );
}
}
}
public function get_per_call_time() {
if ( defined( 'BWFCRM_BULK_ACTION_AS_CALL_SECONDS' ) ) {
return absint( BWFCRM_BULK_ACTION_AS_CALL_SECONDS );
}
return apply_filters( 'bwfan_as_per_call_time', 30 );
}
public function set_log( $log ) {
if ( empty( $log ) ) {
return;
}
$this->logs[] = array(
't' => microtime( true ),
'm' => $log,
);
}
protected function log() {
if ( ! is_array( $this->logs ) || 0 === count( $this->logs ) ) {
return;
}
if ( false === apply_filters( 'bwfan_allow_bulk_action_logging', BWFAN_PRO_Common::is_log_enabled( 'bwfan_bulk_action_logging' ) ) ) {
return;
}
add_filter( 'bwfan_before_making_logs', '__return_true' );
BWFAN_Core()->logger->log( print_r( $this->logs, true ), 'fka-bulk-action' );
$this->logs = [];
}
}
if ( class_exists( 'BWFCRM_Bulk_Action_Handler' ) ) {
BWFCRM_Core::register( 'bulk_action', 'BWFCRM_Bulk_Action_Handler' );
}