PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.8.1
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.8.1
8.8.2 8.8.1 8.8.0 8.7.9 8.7.8 8.7.7 8.7.6 8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 All 538 releases
← All changes | addons/automator/includes/actions/csv-creator-actions.php +252 -252 8.8.0 → 8.8.1 View file →
@@ -1,252 +1,252 @@
1 -<?php
2 -/**
3 - * CSV Creator Actions
4 - *
5 - * @package WPbot_Automator
6 - */
7 -
8 -namespace WPbot_Automator\Actions;
9 -
10 -use WPbot_Automator\Core\Tables;
11 -
12 -if ( ! defined( 'ABSPATH' ) ) {
13 - exit;
14 -}
15 -
16 -/**
17 - * Class CSV_Creator_Actions
18 - *
19 - * Provides three actions that build CSV files and save them to the WordPress
20 - * media library. Each action returns an array merged into $trigger_data so
21 - * downstream nodes can reference:
22 - *
23 - * {csv_url} — public URL of the saved CSV file
24 - * {csv_attachment_id} — WordPress attachment post ID
25 - * {csv_filename} — filename of the saved CSV file
26 - */
27 -class CSV_Creator_Actions extends Action {
28 -
29 - public function __construct() {
30 - $this->id = 'csv_creator';
31 - $this->group = __( 'CSV Creator', 'wpbot-automator' );
32 - }
33 -
34 - public function execute( $action_data, $trigger_data ) {
35 - $action_id = isset( $action_data['actionId'] ) ? $action_data['actionId'] : '';
36 -
37 - switch ( $action_id ) {
38 - case 'csv_from_table': return $this->csv_from_table( $action_data, $trigger_data );
39 - case 'csv_from_json': return $this->csv_from_json( $action_data, $trigger_data );
40 - case 'csv_from_array': return $this->csv_from_array( $action_data, $trigger_data );
41 - default: return false;
42 - }
43 - }
44 -
45 - // ── Sub-actions ──────────────────────────────────────────────────────────
46 -
47 - /**
48 - * Export all (or filtered) records from a wpbot Table to CSV.
49 - *
50 - * Config fields: table_id, filter_col (opt), filter_val (opt), filename (opt).
51 - */
52 - private function csv_from_table( $action_data, $trigger_data ) {
53 - global $wpdb;
54 -
55 - $config = isset( $action_data['config'] ) ? $action_data['config'] : array();
56 - $table_id = absint( $this->parse_tokens( isset( $config['table_id'] ) ? $config['table_id'] : '', $trigger_data ) );
57 -
58 - if ( ! $table_id ) {
59 - return array( 'success' => false, 'message' => 'CSV Creator: table_id is required.' );
60 - }
61 -
62 - $table = Tables::get_table_meta_by_id( $table_id );
63 - if ( ! $table ) {
64 - return array( 'success' => false, 'message' => 'CSV Creator: table not found (' . $table_id . ').' );
65 - }
66 -
67 - $ut = Tables::get_user_table( $table['slug'] );
68 - $filter_col = sanitize_key( $this->parse_tokens( isset( $config['filter_col'] ) ? $config['filter_col'] : '', $trigger_data ) );
69 - $filter_val = sanitize_text_field( $this->parse_tokens( isset( $config['filter_val'] ) ? $config['filter_val'] : '', $trigger_data ) );
70 -
71 - $where = '';
72 - $query_params = array();
73 - $valid_slugs = wp_list_pluck( $table['columns'], 'slug' );
74 -
75 - if ( $filter_col && '' !== $filter_val && in_array( $filter_col, $valid_slugs, true ) ) {
76 - $where = 'WHERE `' . esc_sql( $filter_col ) . '` LIKE %s';
77 - $query_params[] = '%' . $wpdb->esc_like( $filter_val ) . '%';
78 - }
79 -
80 - $sql = "SELECT * FROM `{$ut}` {$where} ORDER BY id ASC";
81 - $records = $query_params
82 - ? $wpdb->get_results( $wpdb->prepare( $sql, ...$query_params ), ARRAY_A )
83 - : $wpdb->get_results( $sql, ARRAY_A );
84 -
85 - // Build header row from column definitions.
86 - $headers = array( 'id' );
87 - foreach ( $table['columns'] as $col ) {
88 - $headers[] = $col['name'];
89 - }
90 - $headers[] = 'created_at';
91 -
92 - // Build CSV rows.
93 - $csv_rows = array( $headers );
94 - foreach ( $records ?: array() as $rec ) {
95 - $row = array( $rec['id'] ?? '' );
96 - foreach ( $table['columns'] as $col ) {
97 - $row[] = $rec[ $col['slug'] ] ?? '';
98 - }
99 - $row[] = $rec['created_at'] ?? '';
100 - $csv_rows[] = $row;
101 - }
102 -
103 - $raw_filename = isset( $config['filename'] ) ? $this->parse_tokens( $config['filename'], $trigger_data ) : '';
104 - $filename = sanitize_file_name( $raw_filename ) ?: ( sanitize_title( $table['name'] ) . '_' . gmdate( 'Y-m-d' ) . '.csv' );
105 -
106 - return $this->save_csv( $csv_rows, $filename );
107 - }
108 -
109 - /**
110 - * Convert a JSON array-of-objects string to CSV.
111 - *
112 - * Config fields: json_data (supports tokens like {response}), filename (opt).
113 - *
114 - * Expected input: '[{"col1":"val","col2":"val"}, ...]'
115 - */
116 - private function csv_from_json( $action_data, $trigger_data ) {
117 - $config = isset( $action_data['config'] ) ? $action_data['config'] : array();
118 - $json_raw = $this->parse_tokens( isset( $config['json_data'] ) ? $config['json_data'] : '', $trigger_data );
119 -
120 - // Strip markdown code-fences in case the data came from an AI action.
121 - $json_raw = preg_replace( '/^```(?:json)?\s*/i', '', trim( $json_raw ) );
122 - $json_raw = preg_replace( '/\s*```$/', '', $json_raw );
123 -
124 - $data = json_decode( $json_raw, true );
125 -
126 - if ( ! is_array( $data ) || empty( $data ) ) {
127 - return array( 'success' => false, 'message' => 'CSV Creator: json_data is not a valid JSON array.' );
128 - }
129 -
130 - // Flatten any nested objects one level deep.
131 - $first_item = reset( $data );
132 - if ( ! is_array( $first_item ) ) {
133 - // Scalar array — wrap each value.
134 - $data = array_map( function( $v ) { return array( 'value' => $v ); }, $data );
135 - $first_item = reset( $data );
136 - }
137 -
138 - $headers = array_keys( $first_item );
139 - $csv_rows = array( $headers );
140 -
141 - foreach ( $data as $row ) {
142 - $csv_rows[] = array_map( function( $h ) use ( $row ) {
143 - $v = isset( $row[ $h ] ) ? $row[ $h ] : '';
144 - return is_array( $v ) ? wp_json_encode( $v ) : (string) $v;
145 - }, $headers );
146 - }
147 -
148 - $raw_filename = isset( $config['filename'] ) ? $this->parse_tokens( $config['filename'], $trigger_data ) : '';
149 - $filename = sanitize_file_name( $raw_filename ) ?: ( 'export_' . gmdate( 'Y-m-d_His' ) . '.csv' );
150 -
151 - return $this->save_csv( $csv_rows, $filename );
152 - }
153 -
154 - /**
155 - * Convert a JSON array-of-arrays string to CSV.
156 - *
157 - * Config fields: array_data, headers (comma-separated, opt), filename (opt).
158 - *
159 - * Expected input: '[["Alice","[email protected]"],["Bob","[email protected]"]]'
160 - */
161 - private function csv_from_array( $action_data, $trigger_data ) {
162 - $config = isset( $action_data['config'] ) ? $action_data['config'] : array();
163 - $raw = $this->parse_tokens( isset( $config['array_data'] ) ? $config['array_data'] : '', $trigger_data );
164 -
165 - // Strip markdown fences.
166 - $raw = preg_replace( '/^```(?:json)?\s*/i', '', trim( $raw ) );
167 - $raw = preg_replace( '/\s*```$/', '', $raw );
168 -
169 - $data = json_decode( $raw, true );
170 -
171 - if ( ! is_array( $data ) || empty( $data ) ) {
172 - return array( 'success' => false, 'message' => 'CSV Creator: array_data is not a valid JSON array.' );
173 - }
174 -
175 - $csv_rows = array();
176 -
177 - // Optional custom headers.
178 - $raw_headers = isset( $config['headers'] ) ? $this->parse_tokens( $config['headers'], $trigger_data ) : '';
179 - if ( ! empty( $raw_headers ) ) {
180 - $csv_rows[] = array_map( 'trim', explode( ',', $raw_headers ) );
181 - }
182 -
183 - foreach ( $data as $row ) {
184 - if ( is_array( $row ) ) {
185 - $csv_rows[] = array_values( $row );
186 - } elseif ( is_scalar( $row ) ) {
187 - $csv_rows[] = array( $row );
188 - }
189 - }
190 -
191 - $raw_filename = isset( $config['filename'] ) ? $this->parse_tokens( $config['filename'], $trigger_data ) : '';
192 - $filename = sanitize_file_name( $raw_filename ) ?: ( 'export_' . gmdate( 'Y-m-d_His' ) . '.csv' );
193 -
194 - return $this->save_csv( $csv_rows, $filename );
195 - }
196 -
197 - // ── Shared helper ────────────────────────────────────────────────────────
198 -
199 - /**
200 - * Build a CSV string from a 2D array and save it to the media library.
201 - *
202 - * @param array $rows Two-dimensional array; first row is the header.
203 - * @param string $filename Target filename including .csv extension.
204 - * @return array Action result array with success, csv_url, csv_attachment_id, csv_filename.
205 - */
206 - private function save_csv( array $rows, $filename ) {
207 - require_once ABSPATH . 'wp-admin/includes/file.php';
208 - require_once ABSPATH . 'wp-admin/includes/media.php';
209 - require_once ABSPATH . 'wp-admin/includes/image.php';
210 -
211 - // Render CSV content in memory.
212 - ob_start();
213 - $fh = fopen( 'php://output', 'w' );
214 - foreach ( $rows as $row ) {
215 - fputcsv( $fh, $row );
216 - }
217 - fclose( $fh );
218 - $csv_content = ob_get_clean();
219 -
220 - // Upload to WordPress uploads directory.
221 - $upload = wp_upload_bits( $filename, null, $csv_content );
222 - if ( ! empty( $upload['error'] ) ) {
223 - //error_log( 'WPbot CSV_Creator: upload failed — ' . $upload['error'] );
224 - return array( 'success' => false, 'message' => 'CSV upload failed: ' . $upload['error'] );
225 - }
226 -
227 - // Register as a media library attachment.
228 - $attachment_id = wp_insert_attachment(
229 - array(
230 - 'post_mime_type' => 'text/csv',
231 - 'post_title' => sanitize_file_name( $filename ),
232 - 'post_content' => '',
233 - 'post_status' => 'inherit',
234 - ),
235 - $upload['file']
236 - );
237 -
238 - if ( is_wp_error( $attachment_id ) ) {
239 - //error_log( 'WPbot CSV_Creator: attachment insert failed — ' . $attachment_id->get_error_message() );
240 - return array( 'success' => false, 'message' => 'Could not add CSV to media library.' );
241 - }
242 -
243 - return array(
244 - 'success' => true,
245 - 'csv_url' => $upload['url'],
246 - 'csv_attachment_id' => $attachment_id,
247 - 'csv_filename' => $filename,
248 - 'csv_path' => $upload['file'],
249 - 'csv_row_count' => max( 0, count( $rows ) - 1 ), // exclude header
250 - );
251 - }
252 -}
1 +<?php
2 +/**
3 + * CSV Creator Actions
4 + *
5 + * @package WPbot_Automator
6 + */
7 +
8 +namespace WPbot_Automator\Actions;
9 +
10 +use WPbot_Automator\Core\Tables;
11 +
12 +if ( ! defined( 'ABSPATH' ) ) {
13 + exit;
14 +}
15 +
16 +/**
17 + * Class CSV_Creator_Actions
18 + *
19 + * Provides three actions that build CSV files and save them to the WordPress
20 + * media library. Each action returns an array merged into $trigger_data so
21 + * downstream nodes can reference:
22 + *
23 + * {csv_url} — public URL of the saved CSV file
24 + * {csv_attachment_id} — WordPress attachment post ID
25 + * {csv_filename} — filename of the saved CSV file
26 + */
27 +class CSV_Creator_Actions extends Action {
28 +
29 + public function __construct() {
30 + $this->id = 'csv_creator';
31 + $this->group = __( 'CSV Creator', 'wpbot-automator' );
32 + }
33 +
34 + public function execute( $action_data, $trigger_data ) {
35 + $action_id = isset( $action_data['actionId'] ) ? $action_data['actionId'] : '';
36 +
37 + switch ( $action_id ) {
38 + case 'csv_from_table': return $this->csv_from_table( $action_data, $trigger_data );
39 + case 'csv_from_json': return $this->csv_from_json( $action_data, $trigger_data );
40 + case 'csv_from_array': return $this->csv_from_array( $action_data, $trigger_data );
41 + default: return false;
42 + }
43 + }
44 +
45 + // ── Sub-actions ──────────────────────────────────────────────────────────
46 +
47 + /**
48 + * Export all (or filtered) records from a wpbot Table to CSV.
49 + *
50 + * Config fields: table_id, filter_col (opt), filter_val (opt), filename (opt).
51 + */
52 + private function csv_from_table( $action_data, $trigger_data ) {
53 + global $wpdb;
54 +
55 + $config = isset( $action_data['config'] ) ? $action_data['config'] : array();
56 + $table_id = absint( $this->parse_tokens( isset( $config['table_id'] ) ? $config['table_id'] : '', $trigger_data ) );
57 +
58 + if ( ! $table_id ) {
59 + return array( 'success' => false, 'message' => 'CSV Creator: table_id is required.' );
60 + }
61 +
62 + $table = Tables::get_table_meta_by_id( $table_id );
63 + if ( ! $table ) {
64 + return array( 'success' => false, 'message' => 'CSV Creator: table not found (' . $table_id . ').' );
65 + }
66 +
67 + $ut = Tables::get_user_table( $table['slug'] );
68 + $filter_col = sanitize_key( $this->parse_tokens( isset( $config['filter_col'] ) ? $config['filter_col'] : '', $trigger_data ) );
69 + $filter_val = sanitize_text_field( $this->parse_tokens( isset( $config['filter_val'] ) ? $config['filter_val'] : '', $trigger_data ) );
70 +
71 + $where = '';
72 + $query_params = array();
73 + $valid_slugs = wp_list_pluck( $table['columns'], 'slug' );
74 +
75 + if ( $filter_col && '' !== $filter_val && in_array( $filter_col, $valid_slugs, true ) ) {
76 + $where = 'WHERE `' . esc_sql( $filter_col ) . '` LIKE %s';
77 + $query_params[] = '%' . $wpdb->esc_like( $filter_val ) . '%';
78 + }
79 +
80 + $sql = "SELECT * FROM `{$ut}` {$where} ORDER BY id ASC";
81 + $records = $query_params
82 + ? $wpdb->get_results( $wpdb->prepare( $sql, ...$query_params ), ARRAY_A )
83 + : $wpdb->get_results( $sql, ARRAY_A );
84 +
85 + // Build header row from column definitions.
86 + $headers = array( 'id' );
87 + foreach ( $table['columns'] as $col ) {
88 + $headers[] = $col['name'];
89 + }
90 + $headers[] = 'created_at';
91 +
92 + // Build CSV rows.
93 + $csv_rows = array( $headers );
94 + foreach ( $records ?: array() as $rec ) {
95 + $row = array( $rec['id'] ?? '' );
96 + foreach ( $table['columns'] as $col ) {
97 + $row[] = $rec[ $col['slug'] ] ?? '';
98 + }
99 + $row[] = $rec['created_at'] ?? '';
100 + $csv_rows[] = $row;
101 + }
102 +
103 + $raw_filename = isset( $config['filename'] ) ? $this->parse_tokens( $config['filename'], $trigger_data ) : '';
104 + $filename = sanitize_file_name( $raw_filename ) ?: ( sanitize_title( $table['name'] ) . '_' . gmdate( 'Y-m-d' ) . '.csv' );
105 +
106 + return $this->save_csv( $csv_rows, $filename );
107 + }
108 +
109 + /**
110 + * Convert a JSON array-of-objects string to CSV.
111 + *
112 + * Config fields: json_data (supports tokens like {response}), filename (opt).
113 + *
114 + * Expected input: '[{"col1":"val","col2":"val"}, ...]'
115 + */
116 + private function csv_from_json( $action_data, $trigger_data ) {
117 + $config = isset( $action_data['config'] ) ? $action_data['config'] : array();
118 + $json_raw = $this->parse_tokens( isset( $config['json_data'] ) ? $config['json_data'] : '', $trigger_data );
119 +
120 + // Strip markdown code-fences in case the data came from an AI action.
121 + $json_raw = preg_replace( '/^```(?:json)?\s*/i', '', trim( $json_raw ) );
122 + $json_raw = preg_replace( '/\s*```$/', '', $json_raw );
123 +
124 + $data = json_decode( $json_raw, true );
125 +
126 + if ( ! is_array( $data ) || empty( $data ) ) {
127 + return array( 'success' => false, 'message' => 'CSV Creator: json_data is not a valid JSON array.' );
128 + }
129 +
130 + // Flatten any nested objects one level deep.
131 + $first_item = reset( $data );
132 + if ( ! is_array( $first_item ) ) {
133 + // Scalar array — wrap each value.
134 + $data = array_map( function( $v ) { return array( 'value' => $v ); }, $data );
135 + $first_item = reset( $data );
136 + }
137 +
138 + $headers = array_keys( $first_item );
139 + $csv_rows = array( $headers );
140 +
141 + foreach ( $data as $row ) {
142 + $csv_rows[] = array_map( function( $h ) use ( $row ) {
143 + $v = isset( $row[ $h ] ) ? $row[ $h ] : '';
144 + return is_array( $v ) ? wp_json_encode( $v ) : (string) $v;
145 + }, $headers );
146 + }
147 +
148 + $raw_filename = isset( $config['filename'] ) ? $this->parse_tokens( $config['filename'], $trigger_data ) : '';
149 + $filename = sanitize_file_name( $raw_filename ) ?: ( 'export_' . gmdate( 'Y-m-d_His' ) . '.csv' );
150 +
151 + return $this->save_csv( $csv_rows, $filename );
152 + }
153 +
154 + /**
155 + * Convert a JSON array-of-arrays string to CSV.
156 + *
157 + * Config fields: array_data, headers (comma-separated, opt), filename (opt).
158 + *
159 + * Expected input: '[["Alice","[email protected]"],["Bob","[email protected]"]]'
160 + */
161 + private function csv_from_array( $action_data, $trigger_data ) {
162 + $config = isset( $action_data['config'] ) ? $action_data['config'] : array();
163 + $raw = $this->parse_tokens( isset( $config['array_data'] ) ? $config['array_data'] : '', $trigger_data );
164 +
165 + // Strip markdown fences.
166 + $raw = preg_replace( '/^```(?:json)?\s*/i', '', trim( $raw ) );
167 + $raw = preg_replace( '/\s*```$/', '', $raw );
168 +
169 + $data = json_decode( $raw, true );
170 +
171 + if ( ! is_array( $data ) || empty( $data ) ) {
172 + return array( 'success' => false, 'message' => 'CSV Creator: array_data is not a valid JSON array.' );
173 + }
174 +
175 + $csv_rows = array();
176 +
177 + // Optional custom headers.
178 + $raw_headers = isset( $config['headers'] ) ? $this->parse_tokens( $config['headers'], $trigger_data ) : '';
179 + if ( ! empty( $raw_headers ) ) {
180 + $csv_rows[] = array_map( 'trim', explode( ',', $raw_headers ) );
181 + }
182 +
183 + foreach ( $data as $row ) {
184 + if ( is_array( $row ) ) {
185 + $csv_rows[] = array_values( $row );
186 + } elseif ( is_scalar( $row ) ) {
187 + $csv_rows[] = array( $row );
188 + }
189 + }
190 +
191 + $raw_filename = isset( $config['filename'] ) ? $this->parse_tokens( $config['filename'], $trigger_data ) : '';
192 + $filename = sanitize_file_name( $raw_filename ) ?: ( 'export_' . gmdate( 'Y-m-d_His' ) . '.csv' );
193 +
194 + return $this->save_csv( $csv_rows, $filename );
195 + }
196 +
197 + // ── Shared helper ────────────────────────────────────────────────────────
198 +
199 + /**
200 + * Build a CSV string from a 2D array and save it to the media library.
201 + *
202 + * @param array $rows Two-dimensional array; first row is the header.
203 + * @param string $filename Target filename including .csv extension.
204 + * @return array Action result array with success, csv_url, csv_attachment_id, csv_filename.
205 + */
206 + private function save_csv( array $rows, $filename ) {
207 + require_once ABSPATH . 'wp-admin/includes/file.php';
208 + require_once ABSPATH . 'wp-admin/includes/media.php';
209 + require_once ABSPATH . 'wp-admin/includes/image.php';
210 +
211 + // Render CSV content in memory.
212 + ob_start();
213 + $fh = fopen( 'php://output', 'w' );
214 + foreach ( $rows as $row ) {
215 + fputcsv( $fh, $row );
216 + }
217 + fclose( $fh );
218 + $csv_content = ob_get_clean();
219 +
220 + // Upload to WordPress uploads directory.
221 + $upload = wp_upload_bits( $filename, null, $csv_content );
222 + if ( ! empty( $upload['error'] ) ) {
223 + //error_log( 'WPbot CSV_Creator: upload failed — ' . $upload['error'] );
224 + return array( 'success' => false, 'message' => 'CSV upload failed: ' . $upload['error'] );
225 + }
226 +
227 + // Register as a media library attachment.
228 + $attachment_id = wp_insert_attachment(
229 + array(
230 + 'post_mime_type' => 'text/csv',
231 + 'post_title' => sanitize_file_name( $filename ),
232 + 'post_content' => '',
233 + 'post_status' => 'inherit',
234 + ),
235 + $upload['file']
236 + );
237 +
238 + if ( is_wp_error( $attachment_id ) ) {
239 + //error_log( 'WPbot CSV_Creator: attachment insert failed — ' . $attachment_id->get_error_message() );
240 + return array( 'success' => false, 'message' => 'Could not add CSV to media library.' );
241 + }
242 +
243 + return array(
244 + 'success' => true,
245 + 'csv_url' => $upload['url'],
246 + 'csv_attachment_id' => $attachment_id,
247 + 'csv_filename' => $filename,
248 + 'csv_path' => $upload['file'],
249 + 'csv_row_count' => max( 0, count( $rows ) - 1 ), // exclude header
250 + );
251 + }
252 +}