PluginProbe
BotWriter – AI Writer & SEO Content Generator / 3.2.8
BotWriter – AI Writer & SEO Content Generator v3.2.8
3.4.10 3.4.9 3.4.8 3.4.7 3.4.6 3.4.4 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 3.3.0 3.2.8 trunk 1.3.0 1.3.1 1.3.2 1.3.3 All 51 releases
botwriter / includes / logs.php

logs.php in BotWriter – AI Writer & SEO Content Generator 3.2.8, at includes/logs.php

490 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit;
4 }
5
6 if (!class_exists('WP_List_Table')) {
7 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
8 }
9
10 function botwriter_logs_page_handler() {
11
12 // Check if the user has the necessary capability
13 if (!current_user_can('manage_options')) {
14 return;
15 }
16
17 if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
18 if (isset($_POST['botwriter_logs_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['botwriter_logs_nonce'])), 'botwriter_logs_action')
19 ) {
20 // The nonce is valid, continue execution
21 } else {
22 wp_die(esc_html__('Security check failed', 'botwriter'));
23 }
24 }
25
26 // Instantiate the logs table class
27 $logs_table = new botwriter_Logs_Table();
28 $logs_table->prepare_items();
29
30 // Display the page
31 echo '<div class="wrap">';
32 echo '<h1>' . esc_html__('BotWriter Logs', 'botwriter') . '</h1>';
33 echo '<div id="countup"></div>';
34
35 echo '<form method="post">';
36 wp_nonce_field('botwriter_logs_action', 'botwriter_logs_nonce');
37 $logs_table->display();
38 echo '</form>';
39 echo '</div>';
40 }
41
42
43
44 class botwriter_Logs_Table extends WP_List_Table {
45
46
47 private $table_data;
48
49 public function __construct() {
50 parent::__construct(array(
51 'singular' => 'log',
52 'plural' => 'logs',
53 'ajax' => false,
54 ));
55 }
56
57 public function get_columns() {
58 return array(
59 'cb' => '<input type="checkbox" />',
60 'created_at' => __('Created At', 'botwriter'),
61 'writer' => __('Writer', 'botwriter'),
62 'task_name' => __('Task Name', 'botwriter'),
63 'task_status' => __('Task Status', 'botwriter'),
64 'aigenerated_title' => __('AI Generated Title', 'botwriter'),
65 'aigenerated_image' => __('AI Generated Image', 'botwriter'),
66 'id_post_published' => __('Post Published', 'botwriter'),
67 'actions' => __('Actions', 'botwriter'),
68 );
69 }
70
71 public function column_cb($item) {
72 return sprintf(
73 '<input type="checkbox" name="log_ids[]" value="%d" />',
74 intval($item['id'])
75 );
76 }
77
78 public function get_bulk_actions() {
79 return array(
80 'bulk_delete' => __('Delete', 'botwriter'),
81 );
82 }
83
84 public function process_bulk_action() {
85 if ('bulk_delete' === $this->current_action()) {
86 if ( ! isset($_POST['botwriter_logs_nonce']) || ! wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['botwriter_logs_nonce'])), 'botwriter_logs_action') ) {
87 return;
88 }
89 if ( ! current_user_can('manage_options') ) {
90 return;
91 }
92 $log_ids = isset($_POST['log_ids']) ? array_map('intval', $_POST['log_ids']) : array();
93 if ( ! empty($log_ids) ) {
94 global $wpdb;
95 $table_name = $wpdb->prefix . 'botwriter_logs';
96 $placeholders = implode(',', array_fill(0, count($log_ids), '%d'));
97 $wpdb->query($wpdb->prepare("DELETE FROM {$table_name} WHERE id IN ({$placeholders})", $log_ids));
98 }
99 }
100 }
101
102 public function column_actions($item) {
103 $log_id = intval($item['id']);
104 return '<button type="button" class="button button-small botwriter-delete-log" data-log-id="' . esc_attr($log_id) . '" title="' . esc_attr__('Delete this log', 'botwriter') . '"><span class="dashicons dashicons-trash" style="vertical-align: middle;"></span></button>';
105 }
106
107 function column_writer($item){
108 $dir_images_writers = BOTWRITER_URL . '/assets/images/writers/';
109 $writer=$item['writer'];
110 $writer = strtolower($writer);
111
112
113 $img= '<img src="' . esc_url($dir_images_writers . $writer . '.jpeg') . '" alt="' . esc_attr($writer) . '" class="writer-photo">';
114 return $img;
115
116 }
117
118 // Create a function for the id_post_published column that shows View and Edit buttons
119 function column_id_post_published($item){
120 $id_post_published = $item['id_post_published'];
121 if ($id_post_published == 0 || empty($id_post_published)) {
122 return '<span style="color: #999;">—</span>';
123 } else {
124 $view_link = get_permalink($id_post_published);
125 $edit_link = get_edit_post_link($id_post_published);
126
127 $buttons = '<div style="display: flex; gap: 5px;">';
128
129 // View button
130 $buttons .= '<a href="' . esc_url($view_link) . '" target="_blank" class="button button-small" title="' . esc_attr__('View post', 'botwriter') . '" style="display: inline-flex; align-items: center; gap: 3px;">';
131 $buttons .= '<span class="dashicons dashicons-visibility" style="font-size: 14px; width: 14px; height: 14px;"></span>';
132 $buttons .= '<span>' . esc_html__('View', 'botwriter') . '</span>';
133 $buttons .= '</a>';
134
135 // Edit button
136 $buttons .= '<a href="' . esc_url($edit_link) . '" class="button button-small" title="' . esc_attr__('Edit post', 'botwriter') . '" style="display: inline-flex; align-items: center; gap: 3px;">';
137 $buttons .= '<span class="dashicons dashicons-edit" style="font-size: 14px; width: 14px; height: 14px;"></span>';
138 $buttons .= '<span>' . esc_html__('Edit', 'botwriter') . '</span>';
139 $buttons .= '</a>';
140
141 $buttons .= '</div>';
142
143 return $buttons;
144 }
145 }
146
147
148 function prepare_items()
149 {
150 //data
151 if ( isset( $_POST['s'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'botwriter_nonce' ) ) {
152 $search_query = sanitize_text_field(wp_unslash($_POST['s']));
153 $this->table_data = $this->get_table_data($search_query);
154 } else {
155 $this->table_data = $this->get_table_data();
156 }
157
158
159 $columns = $this->get_columns();
160 $hidden = ( is_array(get_user_meta( get_current_user_id(), 'managetoplevel_page_list_tablecolumnshidden', true)) ) ? get_user_meta( get_current_user_id(), 'managetoplevel_page_list_tablecolumnshidden', true) : array();
161 $sortable = $this->get_sortable_columns();
162 $primary = 'name';
163 $this->_column_headers = array($columns, $hidden, $sortable, $primary);
164 $this->process_bulk_action();
165 $this->table_data = $this->get_table_data();
166
167 usort($this->table_data, array($this, 'usort_reorder'));
168
169 /* pagination */
170 $per_page = $this->get_items_per_page('elements_per_page', 10);
171 $current_page = $this->get_pagenum();
172 $total_items = count($this->table_data);
173
174 $this->table_data = array_slice($this->table_data, (($current_page - 1) * $per_page), $per_page);
175
176
177
178
179 $this->set_pagination_args(array(
180 'total_items' => $total_items, // total number of items
181 'per_page' => $per_page, // items to show on a page
182 'total_pages' => ceil( $total_items / $per_page ) // use ceil to round up
183 ));
184
185 $this->items = $this->table_data;
186 }
187
188 // Get table data
189 private function get_table_data( $search = '' ) {
190 global $wpdb;
191
192
193 $table = $wpdb->prefix."botwriter_logs";
194
195
196 if ( ! empty( $search ) ) {
197 $prepared_search = $wpdb->esc_like( $search );
198 $prepared_search = '%' . $wpdb->esc_like( $search ) . '%';
199
200
201
202 return $wpdb->get_results(
203 $wpdb->prepare(
204 "SELECT * FROM {$table} WHERE task_name LIKE %s ",
205 $prepared_search
206 ),
207 ARRAY_A
208 );
209 } else {
210 return $wpdb->get_results(
211 $wpdb->prepare("SELECT * FROM {$table} WHERE website_type <> %s", 'super1'),
212 ARRAY_A
213 );
214 }
215 }
216
217
218 // Sorting function
219 function usort_reorder($a, $b)
220 {
221 // If no sort, default to task_name
222 $sanitized_orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : '';
223
224 $orderby = (!empty($sanitized_orderby)) ? $sanitized_orderby : 'created_at';
225
226 $order = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : 'desc ';
227
228 // filtrar order solo asd o desc
229 $order = in_array($order, array('asc', 'desc')) ? $order : 'desc';
230 // filter orderby only allowed columns
231 $orderby = in_array($orderby, array('created_at', 'task_status', 'aigenerated_title')) ? $orderby : 'task_name';
232
233
234
235
236 // Determine sort order
237 $result = strcmp($a[$orderby], $b[$orderby]);
238
239 // Send final sort direction to usort
240 return ($order === 'asc') ? $result : -$result;
241 }
242
243
244 public function column_default($item, $column_name) {
245 // Default handler for columns
246 switch ($column_name) {
247 case 'created_at':
248 case 'task_status':
249 case 'aigenerated_title':
250 return esc_html($item[$column_name]); // Escape output for safety
251 default:
252 return isset($item[$column_name]) ? esc_html($item[$column_name]) : ''; // Fallback for other columns
253 }
254 }
255
256 public function column_task_status($item) {
257 // 4 cases: inqueue, pending, completed, error
258 $task_status = $item['task_status'];
259 $intento_tiempo = array(0=>0,1=>0,2=>5,3=>10,4=>30,5=>60,6=>120,7=>240,8=>480); // minutes
260 $intentosfase1 = $item["intentosfase1"];
261
262 // if it is error show in red and show that it will retry in time * attempts
263 if ($task_status == 'error') {
264 $id_task_server = $item['id_task_server'];
265 $txt= '<span style="color:red;">Error (id server:' . $id_task_server . ')</span>';
266 if ($item["error"]!='') {
267 $txt.= '<br>' . wp_kses_post($item["error"]) . "<br>";
268 }
269 // writenow tasks don't retry, so don't show retry info
270 $task_type = isset($item['task_type']) ? $item['task_type'] : '';
271 if ($intentosfase1 < 8 && $task_type !== 'writenow') { // these are the ones it has taken
272 $tiempo = $intento_tiempo[$intentosfase1+1]; // next attempt
273 $created_at = strtotime($item["created_at"]);
274 $tiempo_siguiente_intento = $created_at + $tiempo*60;
275 $txt.= '<br>Attempt ' . $intentosfase1 . ' of 8';
276 $txt.= '<br>Will retry at ' . gmdate('Y-m-d H:i:s', $tiempo_siguiente_intento);
277 }
278 } else {
279 $txt=esc_html($task_status);
280 }
281
282 return $txt;
283
284 }
285
286 public function column_aigenerated_image($item) {
287 // check if the post is published
288 $id_post_published = $item['id_post_published'];
289 if ($id_post_published != 0) {
290 // get the post image url
291 $post_thumbnail_id = get_post_thumbnail_id($id_post_published);
292 $post_thumbnail_url = wp_get_attachment_image_src($post_thumbnail_id, 'thumbnail');
293 if ($post_thumbnail_url) {
294 return '<img src="' . esc_url($post_thumbnail_url[0]) . '" alt="Post Image" width="50">';
295 }
296 }
297
298 // Render the image or fallback to text if invalid
299 if (filter_var($item['aigenerated_image'], FILTER_VALIDATE_URL)) {
300 return '<img src="' . esc_url($item['aigenerated_image']) . '" alt="Generated Image" width="50">';
301 } else {
302 return esc_html($item['aigenerated_image']);
303 }
304
305 }
306
307 public function column_task_name($item) {
308 if ($item['website_type']=="super2") {
309 $txt = esc_html($item['task_name']);
310 $txt .= '<br><span style="color:blue;">' . esc_html($item['title_prompt']) . '</span>';
311 return $txt;
312 } else {
313 return esc_html($item['task_name']);
314 }
315
316
317 }
318
319
320 public function no_items() {
321 esc_html__('No logs found.', 'botwriter');
322 }
323
324 public function get_sortable_columns() {
325 return array(
326 'created_at' => array('created_at', true),
327
328 'task_status' => array('task_status', false),
329 'aigenerated_title' => array('aigenerated_title', false),
330 );
331 }
332
333
334 }
335
336
337 function botwriter_get_logs_links($id_task) {
338 global $wpdb;
339
340
341 $links = $wpdb->get_results($wpdb->prepare("SELECT link_post_original FROM {$wpdb->prefix}botwriter_logs WHERE id_task = %d ORDER BY id DESC LIMIT 50", $id_task), ARRAY_A);
342 $links_array = [];
343 if (empty($links)) {
344 return false;
345 } else {
346 foreach ($links as $link) {
347 if ($link['link_post_original'] != '') {
348 $links_array[] = $link['link_post_original'];
349 }
350 }
351 }
352 return $links_array;
353
354 }
355
356
357 function botwriter_get_logs_titles($id_task) {
358 global $wpdb;
359
360
361 $results = $wpdb->get_results($wpdb->prepare("SELECT aigenerated_title FROM {$wpdb->prefix}botwriter_logs WHERE id_task = %d ORDER BY id DESC LIMIT 50", $id_task), ARRAY_A);
362 $titles_array = [];
363 if (empty($results)) {
364 return false;
365 } else {
366 foreach ($results as $result) {
367 if ($result['aigenerated_title'] != '') {
368 $titles_array[] = $result['aigenerated_title'];
369 //echo "<br>title in the db: " . $result['aigenerated_title'];
370 }
371 }
372 }
373 return $titles_array;
374
375 }
376
377
378
379 // Register a log in the botwriter_logs table (insert or update)
380 function botwriter_logs_register($data, $id = null) {
381 global $wpdb;
382 $table_name = $wpdb->prefix . 'botwriter_logs';
383
384 // Validate that $data is an array
385 if (!is_array($data)) {
386 return false; // Or throw an exception as needed
387 }
388
389 // List of allowed keys
390 $allowed_keys = array(
391 'id_task',
392 'id_task_server',
393 'post_status',
394 'task_name',
395 'task_type',
396 'writer',
397 'narration',
398 'custom_style',
399 'post_language',
400 'post_length',
401 'link_post_original',
402 'id_post_published',
403 'task_status',
404 'error',
405 'website_name',
406 'website_type',
407 'domain_name',
408 'post_type',
409 'category_id',
410 'taxonomy_data',
411 'website_category_id',
412 'aigenerated_title',
413 'aigenerated_content',
414 'aigenerated_tags',
415 'aigenerated_image',
416 'post_count',
417 'post_order',
418 'title_prompt',
419 'content_prompt',
420 'tags_prompt',
421 'image_prompt',
422 'image_generating_status',
423 'author_selection',
424 'news_time_published',
425 'news_language',
426 'news_country',
427 'news_keyword',
428 'news_source',
429 'rss_source',
430 'ai_keywords',
431 'disable_ai_images',
432 'template_id',
433 'intentosfase1',
434 'last_execution_time'
435
436 );
437
438 // Create the array with only the existing values in $data
439 $insert_data = array();
440 foreach ($allowed_keys as $key) {
441 if (isset($data[$key])) {
442 $insert_data[$key] = $data[$key];
443 }
444 }
445
446 if ($id) {
447 // Update the existing record
448 $where = array('id' => $id);
449 $updated = $wpdb->update($table_name, $insert_data, $where);
450
451 // If task_status is 'completed', reset the errors notice
452 if (isset($insert_data['task_status']) && $insert_data['task_status'] === 'completed') {
453 if (function_exists('botwriter_reset_errors_notice_dismissed')) {
454 botwriter_reset_errors_notice_dismissed();
455 }
456 }
457
458 // Return the result of the update
459 return $updated !== false ? $id : false;
460 } else {
461 // Insert a new record
462 // Add the creation date
463 $current_time = current_time('mysql');
464 $insert_data['created_at'] = $current_time;
465
466 $wpdb->insert($table_name, $insert_data);
467
468 // If the new log is 'completed', reset the errors notice dismissed flag
469 // This allows the notice to reappear if errors occur again later
470 if (isset($insert_data['task_status']) && $insert_data['task_status'] === 'completed') {
471 if (function_exists('botwriter_reset_errors_notice_dismissed')) {
472 botwriter_reset_errors_notice_dismissed();
473 }
474 }
475
476 // Return the ID of the new record
477 return $wpdb->insert_id;
478 }
479 }
480
481 // Function that given an id returns an array with the data of a log
482 function botwriter_logs_get($id) {
483 global $wpdb;
484 $table_name = $wpdb->prefix . 'botwriter_logs';
485
486 $log = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $id), ARRAY_A);
487
488 return $log;
489 }
490