__( 'rule', 'aicoso-dynamic-pricing-for-woocommerce' ),
'plural' => __( 'rules', 'aicoso-dynamic-pricing-for-woocommerce' ),
'ajax' => false,
)
);
}
/**
* Get safe table name for SQL queries.
*
* @param string $table Base table name.
* @return string Full table name with prefix.
*/
private function get_table_name( $table ) {
global $wpdb;
return $wpdb->prefix . $table;
}
/**
* Helper method for cached database queries.
*
* @param string $cache_key The cache key.
* @param callable $query_func The query function to execute if cache miss.
* @param int $cache_expire Cache expiration time in seconds (default: 300).
* @return mixed The query result.
*/
private function cached_query( $cache_key, $query_func, $cache_expire = 300 ) {
$result = wp_cache_get( $cache_key, 'dp_aicoso_rules_list' );
if ( false === $result ) {
$result = call_user_func( $query_func );
wp_cache_set( $cache_key, $result, 'dp_aicoso_rules_list', $cache_expire );
}
return $result;
}
/**
* Get table columns.
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '',
'rule_name' => __( 'Rule Name', 'aicoso-dynamic-pricing-for-woocommerce' ),
'rule_type' => __( 'Type', 'aicoso-dynamic-pricing-for-woocommerce' ),
'priority' => __( 'Priority', 'aicoso-dynamic-pricing-for-woocommerce' ),
'status' => __( 'Status', 'aicoso-dynamic-pricing-for-woocommerce' ),
'applies_to' => __( 'Applies To', 'aicoso-dynamic-pricing-for-woocommerce' ),
'discount' => __( 'Discount', 'aicoso-dynamic-pricing-for-woocommerce' ),
'date_range' => __( 'Date Range', 'aicoso-dynamic-pricing-for-woocommerce' ),
'actions' => __( 'Actions', 'aicoso-dynamic-pricing-for-woocommerce' ),
);
}
/**
* Get sortable columns.
*
* @return array
*/
public function get_sortable_columns() {
return array(
'rule_name' => array( 'rule_name', false ),
'rule_type' => array( 'rule_type', false ),
'priority' => array( 'priority', true ),
'status' => array( 'rule_status', false ),
);
}
/**
* Get bulk actions.
*
* @return array
*/
public function get_bulk_actions() {
return array(
'activate' => __( 'Activate', 'aicoso-dynamic-pricing-for-woocommerce' ),
'deactivate' => __( 'Deactivate', 'aicoso-dynamic-pricing-for-woocommerce' ),
'delete' => __( 'Delete', 'aicoso-dynamic-pricing-for-woocommerce' ),
'duplicate' => __( 'Duplicate', 'aicoso-dynamic-pricing-for-woocommerce' ),
);
}
/**
* Prepare items for display.
*/
public function prepare_items() {
global $wpdb;
$per_page = $this->get_items_per_page( 'dp_aicoso_rules_per_page', 20 );
$current_page = $this->get_pagenum();
// Set column headers.
$this->_column_headers = array(
$this->get_columns(),
array(), // Hidden columns.
$this->get_sortable_columns(),
);
// Process bulk actions.
$this->process_bulk_action();
// Prepare query.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WP_List_Table handles nonce verification.
$orderby = ! empty( $_REQUEST['orderby'] ) ? sanitize_sql_orderby( wp_unslash( $_REQUEST['orderby'] ) ) : 'priority';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WP_List_Table handles nonce verification.
$order = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) : 'DESC';
$offset = ( $current_page - 1 ) * $per_page;
// Get total items with caching.
$total_items = $this->cached_query(
'dp_aicoso_rules_total_count',
function () use ( $wpdb ) {
$table_name = $this->get_table_name( 'dp_aicoso_rules' );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Query is cached via cached_query(), table name is safe.
return $wpdb->get_var( 'SELECT COUNT(*) FROM ' . esc_sql( $table_name ) );
}
);
// Get items with caching.
$this->items = $this->cached_query(
'dp_aicoso_rules_page_' . $current_page . '_orderby_' . $orderby . '_order_' . $order . '_per_' . $per_page,
function () use ( $wpdb, $orderby, $order, $per_page, $offset ) {
$table_name = $this->get_table_name( 'dp_aicoso_rules' );
// Define allowed ORDER BY clauses to avoid any variable interpolation.
$allowed_order_clauses = array(
'id ASC',
'id DESC',
'rule_name ASC',
'rule_name DESC',
'rule_type ASC',
'rule_type DESC',
'priority ASC',
'priority DESC',
'status ASC',
'status DESC',
'created_at ASC',
'created_at DESC',
);
$order_clause = $orderby . ' ' . $order;
if ( ! in_array( $order_clause, $allowed_order_clauses, true ) ) {
$order_clause = 'priority DESC'; // Safe default.
}
// Use fixed SQL queries with no variable interpolation - switch based on validated clause.
switch ( $order_clause ) {
case 'id ASC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY rule_id ASC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'id DESC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY rule_id DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'rule_name ASC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY rule_name ASC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'rule_name DESC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY rule_name DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'rule_type ASC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY rule_type ASC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'rule_type DESC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY rule_type DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'priority ASC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY priority ASC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'priority DESC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY priority DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'status ASC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY status ASC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'status DESC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY status DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'created_at ASC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY created_at ASC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
case 'created_at DESC':
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY created_at DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
default:
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached, table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . $wpdb->prefix . 'dp_aicoso_rules ORDER BY priority DESC LIMIT %d OFFSET %d',
$per_page,
$offset
),
ARRAY_A
);
}
},
60 // Short cache for list table data.
);
// Set pagination.
$this->set_pagination_args(
array(
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => ceil( $total_items / $per_page ),
)
);
}
/**
* Process bulk actions.
*/
private function process_bulk_action() {
// Security check.
if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'bulk-' . $this->_args['plural'] ) ) {
return;
}
$action = $this->current_action();
if ( ! $action ) {
return;
}
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce already verified above.
$rule_ids = isset( $_POST['rule'] ) ? array_map( 'intval', wp_unslash( $_POST['rule'] ) ) : array();
if ( empty( $rule_ids ) ) {
return;
}
global $wpdb;
$table_name = $this->get_table_name( 'dp_aicoso_rules' );
switch ( $action ) {
case 'delete':
foreach ( $rule_ids as $rule_id ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Write operation
$wpdb->delete( $table_name, array( 'rule_id' => $rule_id ), array( '%d' ) );
}
// Clear cache after delete.
break;
case 'activate':
foreach ( $rule_ids as $rule_id ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Write operation
$wpdb->update(
$table_name,
array( 'rule_status' => 'active' ),
array( 'rule_id' => $rule_id ),
array( '%s' ),
array( '%d' )
);
}
// Clear cache after activate.
wp_cache_flush_group( 'dp_aicoso_rules_list' );
break;
case 'deactivate':
foreach ( $rule_ids as $rule_id ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Write operation
$wpdb->update(
$table_name,
array( 'rule_status' => 'inactive' ),
array( 'rule_id' => $rule_id ),
array( '%s' ),
array( '%d' )
);
}
// Clear cache after deactivate.
wp_cache_flush_group( 'dp_aicoso_rules_list' );
break;
case 'duplicate':
foreach ( $rule_ids as $rule_id ) {
$this->duplicate_rule( $rule_id );
}
// Clear cache after duplicate.
wp_cache_flush_group( 'dp_aicoso_rules_list' );
break;
}
// Clear price calculator cache after bulk actions.
$calculator = DP_AICOSO_Price_Calculator::get_instance();
$calculator->clear_cache();
}
/**
* Duplicate a rule.
*
* @param int $rule_id Rule ID to duplicate.
*/
private function duplicate_rule( $rule_id ) {
global $wpdb;
$table_name = $this->get_table_name( 'dp_aicoso_rules' );
// Get original rule with caching.
$rule = $this->cached_query(
'dp_aicoso_rule_' . $rule_id,
function () use ( $wpdb, $table_name, $rule_id ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Query is cached via cached_query(), table name is safe.
return $wpdb->get_row(
$wpdb->prepare(
'SELECT * FROM ' . esc_sql( $table_name ) . ' WHERE rule_id = %d',
$rule_id
),
ARRAY_A
);
}
);
if ( ! $rule ) {
return;
}
// Remove ID and modify name.
unset( $rule['rule_id'] );
$rule['rule_name'] = $rule['rule_name'] . ' (Copy)';
$rule['rule_status'] = 'inactive'; // Start as inactive.
// Insert duplicate.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Write operation.
$wpdb->insert( $table_name, $rule );
// Duplicate relationships if needed.
$new_rule_id = $wpdb->insert_id;
if ( $new_rule_id ) {
$this->duplicate_rule_relationships( $rule_id, $new_rule_id );
// Clear cache after duplicate.
wp_cache_flush_group( 'dp_aicoso_rules_list' );
}
}
/**
* Duplicate rule relationships.
*
* @param int $old_rule_id Original rule ID.
* @param int $new_rule_id New rule ID.
*/
private function duplicate_rule_relationships( $old_rule_id, $new_rule_id ) {
global $wpdb;
$relationships_table = $this->get_table_name( 'dp_aicoso_rule_relationships' );
// Get relationships with caching.
$relationships = $this->cached_query(
'dp_aicoso_rule_relationships_' . $old_rule_id,
function () use ( $wpdb, $relationships_table, $old_rule_id ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Query is cached via cached_query(), table name is safe.
return $wpdb->get_results(
$wpdb->prepare(
'SELECT object_id, object_type FROM ' . esc_sql( $relationships_table ) . ' WHERE rule_id = %d',
$old_rule_id
),
ARRAY_A
);
}
);
foreach ( $relationships as $relationship ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Write operation
$wpdb->insert(
$relationships_table,
array(
'rule_id' => $new_rule_id,
'object_id' => $relationship['object_id'],
'object_type' => $relationship['object_type'],
)
);
}
}
/**
* Default column display.
*
* @param array $item Item data.
* @param string $column_name Column name.
* @return string
*/
public function column_default( $item, $column_name ) {
switch ( $column_name ) {
case 'priority':
return intval( $item['priority'] );
case 'date_range':
return $this->format_date_range( $item );
default:
return isset( $item[ $column_name ] ) ? $item[ $column_name ] : '';
}
}
/**
* Checkbox column.
*
* @param array $item Item data.
* @return string
*/
public function column_cb( $item ) {
return sprintf(
'',
$item['rule_id']
);
}
/**
* Rule name column.
*
* @param array $item Item data.
* @return string
*/
public function column_rule_name( $item ) {
$edit_url = admin_url( 'admin.php?page=dp-aicoso-add-rule&rule_id=' . $item['rule_id'] );
$actions = array(
'edit' => sprintf( '%s', $edit_url, __( 'Edit', 'aicoso-dynamic-pricing-for-woocommerce' ) ),
'duplicate' => sprintf( '%s', $item['rule_id'], __( 'Duplicate', 'aicoso-dynamic-pricing-for-woocommerce' ) ),
'delete' => sprintf( '%s', $item['rule_id'], __( 'Delete', 'aicoso-dynamic-pricing-for-woocommerce' ) ),
);
return sprintf(
'%s %s',
$edit_url,
esc_html( $item['rule_name'] ),
$this->row_actions( $actions )
);
}
/**
* Rule type column.
*
* @param array $item Item data.
* @return string
*/
public function column_rule_type( $item ) {
$types = array(
'product' => __( 'Product', 'aicoso-dynamic-pricing-for-woocommerce' ),
'category' => __( 'Category', 'aicoso-dynamic-pricing-for-woocommerce' ),
'role' => __( 'User Role', 'aicoso-dynamic-pricing-for-woocommerce' ),
'time' => __( 'Time-based', 'aicoso-dynamic-pricing-for-woocommerce' ),
'custom' => __( 'Custom', 'aicoso-dynamic-pricing-for-woocommerce' ),
);
$type = isset( $types[ $item['rule_type'] ] ) ? $types[ $item['rule_type'] ] : $item['rule_type'];
return sprintf(
'%s',
esc_attr( $item['rule_type'] ),
esc_html( $type )
);
}
/**
* Status column.
*
* @param array $item Item data.
* @return string
*/
public function column_status( $item ) {
$status_labels = array(
'active' => __( 'Active', 'aicoso-dynamic-pricing-for-woocommerce' ),
'inactive' => __( 'Inactive', 'aicoso-dynamic-pricing-for-woocommerce' ),
'scheduled' => __( 'Scheduled', 'aicoso-dynamic-pricing-for-woocommerce' ),
);
$status = isset( $status_labels[ $item['rule_status'] ] ) ? $status_labels[ $item['rule_status'] ] : $item['rule_status'];
return sprintf(
'%s',
esc_attr( $item['rule_status'] ),
esc_html( $status )
);
}
/**
* Applies to column.
*
* @param array $item Item data.
* @return string
*/
public function column_applies_to( $item ) {
global $wpdb;
$relationships_table = $this->get_table_name( 'dp_aicoso_rule_relationships' );
// Get relationships with caching.
$relationships = $this->cached_query(
'dp_aicoso_rule_applies_to_' . $item['rule_id'],
function () use ( $wpdb, $relationships_table, $item ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query is cached via cached_query(). Table name is safely escaped with esc_sql().
return $wpdb->get_results(
$wpdb->prepare(
'SELECT * FROM ' . esc_sql( $relationships_table ) . ' WHERE rule_id = %d',
$item['rule_id']
)
);
}
);
if ( empty( $relationships ) ) {
return __( 'All products', 'aicoso-dynamic-pricing-for-woocommerce' );
}
$applies_to = array();
foreach ( $relationships as $rel ) {
if ( 'product' === $rel->object_type ) {
$product = wc_get_product( $rel->object_id );
if ( $product ) {
$applies_to[] = $product->get_name();
}
} elseif ( 'category' === $rel->object_type ) {
$term = get_term( $rel->object_id, 'product_cat' );
if ( $term && ! is_wp_error( $term ) ) {
$applies_to[] = $term->name . ' (Category)';
}
} elseif ( 0 === strpos( $rel->object_type, 'role:' ) ) {
$role = str_replace( 'role:', '', $rel->object_type );
$applies_to[] = ucfirst( $role ) . ' (Role)';
}
}
return ! empty( $applies_to ) ? implode( ', ', $applies_to ) : __( 'Various', 'aicoso-dynamic-pricing-for-woocommerce' );
}
/**
* Discount column.
*
* @param array $item Item data.
* @return string
*/
public function column_discount( $item ) {
$adjustments = ! empty( $item['adjustments'] ) ? json_decode( $item['adjustments'], true ) : array();
if ( empty( $adjustments ) ) {
return '-';
}
// Check for quantity ranges first.
if ( ! empty( $adjustments['quantity_ranges'] ) && is_array( $adjustments['quantity_ranges'] ) ) {
$ranges = $adjustments['quantity_ranges'];
$range_count = count( $ranges );
// Find min and max discounts for display.
$min_discount = null;
$max_discount = null;
$discount_type = null;
foreach ( $ranges as $range ) {
if ( isset( $range['discount_value'] ) && '' !== $range['discount_value'] ) {
$value = floatval( $range['discount_value'] );
$type = isset( $range['discount_type'] ) ? $range['discount_type'] : 'percentage';
if ( null === $discount_type ) {
$discount_type = $type;
}
if ( null === $min_discount || $value < $min_discount ) {
$min_discount = $value;
}
if ( null === $max_discount || $value > $max_discount ) {
$max_discount = $value;
}
}
}
// Format the display.
if ( null !== $min_discount && null !== $max_discount ) {
if ( $min_discount == $max_discount ) {
// All ranges have same discount.
if ( 'percentage' === $discount_type ) {
/* translators: %1$s: Discount percentage, %2$d: Number of tiers */
return sprintf( __( '%1$s%% (%2$d tiers)', 'aicoso-dynamic-pricing-for-woocommerce' ), $min_discount, $range_count );
} else {
/* translators: %1$s: Price amount, %2$d: Number of tiers */
return sprintf( __( '%1$s (%2$d tiers)', 'aicoso-dynamic-pricing-for-woocommerce' ), wc_price( $min_discount ), $range_count );
}
} elseif ( 'percentage' === $discount_type ) {
// Different discounts in ranges.
/* translators: %1$s: Min discount, %2$s: Max discount, %3$d: Number of tiers */
return sprintf( __( '%1$s-%2$s%% (%3$d tiers)', 'aicoso-dynamic-pricing-for-woocommerce' ), $min_discount, $max_discount, $range_count );
} else {
/* translators: %1$s: Min price, %2$s: Max price, %3$d: Number of tiers */
return sprintf( __( '%1$s-%2$s (%3$d tiers)', 'aicoso-dynamic-pricing-for-woocommerce' ), wc_price( $min_discount ), wc_price( $max_discount ), $range_count );
}
}
// If we couldn't determine discounts from ranges, show tier count.
/* translators: %d: number of quantity tiers */
return sprintf( __( '%d quantity tiers', 'aicoso-dynamic-pricing-for-woocommerce' ), $range_count );
}
// Check for new array format [{'type': 'percentage', 'value': 40}].
if ( isset( $adjustments[0] ) && is_array( $adjustments[0] ) ) {
$first_adjustment = $adjustments[0];
if ( isset( $first_adjustment['type'] ) && isset( $first_adjustment['value'] ) ) {
$type = $first_adjustment['type'];
$value = $first_adjustment['value'];
if ( 'percentage' === $type ) {
return $value . '%';
} elseif ( 'fixed' === $type ) {
return wc_price( $value );
} elseif ( 'fixed_price' === $type ) {
return wc_price( $value ) . ' ' . __( '(Fixed)', 'aicoso-dynamic-pricing-for-woocommerce' );
}
// If value is 0 or empty, still show it.
if ( 0 == $value ) {
if ( 'percentage' === $type ) {
return '0%';
} else {
return wc_price( 0 );
}
}
}
}
// Try old format for backward compatibility.
if ( isset( $adjustments['discount_type'] ) && isset( $adjustments['discount_value'] ) ) {
if ( 'percentage' === $adjustments['discount_type'] ) {
return $adjustments['discount_value'] . '%';
} elseif ( 'fixed' === $adjustments['discount_type'] ) {
return wc_price( $adjustments['discount_value'] );
} elseif ( 'fixed_price' === $adjustments['discount_type'] ) {
return wc_price( $adjustments['discount_value'] ) . ' ' . __( '(Fixed)', 'aicoso-dynamic-pricing-for-woocommerce' );
}
}
// Check for default adjustment.
if ( isset( $adjustments['default'] ) ) {
$default = $adjustments['default'];
if ( 'percentage' === $default['type'] ) {
return $default['value'] . '%';
} elseif ( 'fixed' === $default['type'] ) {
return wc_price( $default['value'] );
}
}
return __( 'Variable', 'aicoso-dynamic-pricing-for-woocommerce' );
}
/**
* Actions column.
*
* @param array $item Item data.
* @return string
*/
public function column_actions( $item ) {
$actions = array();
// Toggle status button.
if ( 'active' === $item['rule_status'] ) {
$actions[] = sprintf(
'',
$item['rule_id'],
__( 'Deactivate', 'aicoso-dynamic-pricing-for-woocommerce' )
);
} else {
$actions[] = sprintf(
'',
$item['rule_id'],
__( 'Activate', 'aicoso-dynamic-pricing-for-woocommerce' )
);
}
// Edit button.
$actions[] = sprintf(
'%s',
admin_url( 'admin.php?page=dp-aicoso-add-rule&rule_id=' . $item['rule_id'] ),
__( 'Edit', 'aicoso-dynamic-pricing-for-woocommerce' )
);
return implode( ' ', $actions );
}
/**
* Format date range.
*
* @param array $item Item data.
* @return string
*/
private function format_date_range( $item ) {
$start = ! empty( $item['start_date'] ) ? $item['start_date'] : null;
$end = ! empty( $item['end_date'] ) ? $item['end_date'] : null;
if ( ! $start && ! $end ) {
return __( 'Always', 'aicoso-dynamic-pricing-for-woocommerce' );
}
$output = '';
if ( $start ) {
$output .= date_i18n( get_option( 'date_format' ), strtotime( $start ) );
} else {
$output .= __( 'Now', 'aicoso-dynamic-pricing-for-woocommerce' );
}
$output .= ' - ';
if ( $end ) {
$output .= date_i18n( get_option( 'date_format' ), strtotime( $end ) );
} else {
$output .= __( 'Forever', 'aicoso-dynamic-pricing-for-woocommerce' );
}
return $output;
}
/**
* Display when no items found.
*/
public function no_items() {
esc_html_e( 'No pricing rules found. Create your first rule to get started!', 'aicoso-dynamic-pricing-for-woocommerce' );
}
}