From b5a4bd4e3ff3176220d02ae588ac5b1c8ca402ba Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Tue, 30 Dec 2025 18:51:32 +0530 Subject: [PATCH 1/4] feat: add cleanup records --- .../abstract/class-rop-model-abstract.php | 2 +- includes/admin/class-rop-rest-api.php | 14 +++ .../admin/models/class-rop-services-model.php | 23 ++++ includes/class-rop-i18n.php | 4 + vue/src/models/rop_store.js | 3 + vue/src/vue-elements/accounts-tab-panel.vue | 102 +++++++++++++++++- 6 files changed, 145 insertions(+), 3 deletions(-) diff --git a/includes/admin/abstract/class-rop-model-abstract.php b/includes/admin/abstract/class-rop-model-abstract.php index ea9a47180..f3a8238da 100644 --- a/includes/admin/abstract/class-rop-model-abstract.php +++ b/includes/admin/abstract/class-rop-model-abstract.php @@ -92,7 +92,7 @@ protected function set( $key, $value = '', $refresh = false ) { $this->data[ $key ] = apply_filters( 'rop_set_key_' . $key, $value ); - return update_option( $this->namespace, $this->data ); + return update_option( $this->namespace, $this->data, false ); } diff --git a/includes/admin/class-rop-rest-api.php b/includes/admin/class-rop-rest-api.php index c90649aa5..e9d118921 100644 --- a/includes/admin/class-rop-rest-api.php +++ b/includes/admin/class-rop-rest-api.php @@ -1642,6 +1642,20 @@ private function add_account_bluesky( $data ) { return $this->response->to_array(); } + /** + * API method called to cleanup services. + * + * @access private + * @return array + */ + public function cleanup_accounts() { + $model = new Rop_Services_Model(); + $this->response->set_code( '200' ) + ->set_data( $model->cleanup_accounts() ); + + return $this->response->to_array(); + } + /** * Share API method. * diff --git a/includes/admin/models/class-rop-services-model.php b/includes/admin/models/class-rop-services-model.php index 0bb8a3f7f..a02016689 100644 --- a/includes/admin/models/class-rop-services-model.php +++ b/includes/admin/models/class-rop-services-model.php @@ -37,6 +37,13 @@ class Rop_Services_Model extends Rop_Model_Abstract { */ private $accounts_namespace = 'active_accounts'; + /** + * Cleanup account count. + * + * @access private + * @var int $cleanup_account_count + */ + private $cleanup_account_count = 1000; /** * Utility method to clear authenticated services. @@ -520,4 +527,20 @@ public function find_account( $account_id ) { return false; } + /** + * Utility method to cleanup authenticated services. + * + * @access public + * @return array + */ + public function cleanup_accounts() { + $services = $this->get( $this->services_namespace ); + + if ( count( $services ) > $this->cleanup_account_count ) { + $services = array_slice( $services, -( $this->cleanup_account_count ), null, true ); + $this->set( $this->services_namespace, $services ); + } + + return $services; + } } diff --git a/includes/class-rop-i18n.php b/includes/class-rop-i18n.php index 338b1f06d..74323f095 100644 --- a/includes/class-rop-i18n.php +++ b/includes/class-rop-i18n.php @@ -139,6 +139,10 @@ public static function get_labels( $key = '' ) { 'upsell_bz_service_body' => __( 'We\'re sorry, %1$s is not available on your plan. Please upgrade to the business plan to unlock all these features and get more traffic.', 'tweet-old-post' ), 'search_account' => __( 'Search account', 'tweet-old-post' ), 'no_account_found' => __( 'No account found for search', 'tweet-old-post' ), + 'cleanup_cta' => __( 'Cleanup accounts', 'tweet-old-post' ), + 'cleanup_title' => __( 'Clean Up Accounts', 'tweet-old-post' ), + 'cleanup_description' => __( 'This will remove older account records and keep only the most recent 1,000 accounts. This helps improve performance and reduce stored data.', 'tweet-old-post' ), + 'cleanup_now' => __( 'Cleanup now', 'tweet-old-post' ), ), 'settings' => array( 'yes_text' => __( 'Yes', 'tweet-old-post' ), diff --git a/vue/src/models/rop_store.js b/vue/src/models/rop_store.js index a82262670..81ff218b7 100644 --- a/vue/src/models/rop_store.js +++ b/vue/src/models/rop_store.js @@ -270,6 +270,9 @@ export default new Vuex.Store({ case 'toggle_tracking': break + case 'cleanup_accounts': + state.authenticatedServices = stateData; + break; default: Vue.$log.error('No state request for ', requestName); } diff --git a/vue/src/vue-elements/accounts-tab-panel.vue b/vue/src/vue-elements/accounts-tab-panel.vue index ad2cb37be..8eb00b265 100644 --- a/vue/src/vue-elements/accounts-tab-panel.vue +++ b/vue/src/vue-elements/accounts-tab-panel.vue @@ -89,6 +89,20 @@
+
+ @@ -142,7 +182,8 @@ labels: this.$store.state.labels.accounts, upsell_link: ropApiSettings.upsell_link, pro_installed: ropApiSettings.pro_installed, - postTimeout: '' + postTimeout: '', + cleanupModal: false, } }, computed: { @@ -189,7 +230,12 @@ }, hasActiveAccountsLimitation: function () { return !this.pro_installed && this.accountsCount >= 2 && this.checkLicense ; - } + }, + cleanupModalClass: function () { + return { + 'active': this.cleanupModal === true + } + }, }, mounted: function () { if (0 === this.is_preloading) { @@ -228,6 +274,33 @@ Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) }) }, + openCleanupModal: function() { + this.cleanupModal = true; + }, + closeCleanupModal: function() { + this.cleanupModal = false; + }, + cleanupAccount: function() { + if (this.is_loading) { + this.$log.warn('Request in progress...Bail'); + return; + } + this.is_loading = true; + this.$store.dispatch('fetchAJAXPromise', { + req: 'cleanup_accounts', + data: {} + }).then(response => { + this.is_loading = false; + this.cleanupModal = false; + if (this.$parent.start_status === true) { + // Stop sharing process if enabled. + this.$parent.togglePosting(); + } + }, error => { + this.is_loading = false; + Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) + }) + }, filteredAccounts: function(accounts) { const result = {}; const query = this.searchAccount?.toLowerCase() || ''; @@ -273,6 +346,31 @@ margin-bottom: 15px; } + #rop_core .rop-cleanup-modal .modal-container{ + max-width: 500px; + padding: 25px; + + .modal-title, .modal-footer{ + text-align: center; + } + .btn-success{ + border:none; + background-color:#00a32a; + color: #fff; + padding: 0.5rem 1rem; + height: auto; + display: inline; + } + .btn-success:hover{ + background-color:#009528; + } + .modal-body{ + font-size: 0.7rem; + margin: 10px 30px; + padding: 0px; + } + } + @media ( max-width: 600px ) { #rop_core .panel-body .text-gray { margin-bottom: 10px; From 6a7a352493b02c670b9a88c4f234000a56c6d9fd Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Tue, 13 Jan 2026 17:48:46 +0530 Subject: [PATCH 2/4] feat: add cleanup logs --- includes/admin/class-rop-logger.php | 29 ++++- includes/admin/class-rop-rest-api.php | 8 +- .../admin/models/class-rop-services-model.php | 25 ----- includes/class-rop-i18n.php | 11 +- vue/src/models/rop_store.js | 5 +- vue/src/vue-elements/accounts-tab-panel.vue | 98 ----------------- vue/src/vue-elements/logs-tab-panel.vue | 100 +++++++++++++++++- 7 files changed, 140 insertions(+), 136 deletions(-) diff --git a/includes/admin/class-rop-logger.php b/includes/admin/class-rop-logger.php index 209fc69de..63f40c4c4 100644 --- a/includes/admin/class-rop-logger.php +++ b/includes/admin/class-rop-logger.php @@ -29,6 +29,14 @@ class Rop_Logger { */ private $stream; + /** + * Holds the log namespace. + * + * @access private + * @var string $log_namespace Defaults 'rop_logs'. + */ + private $log_namespace = 'rop_logs'; + /** * Rop_Logger constructor. * Instantiate the Logger with specified formatter and stream. @@ -38,7 +46,7 @@ class Rop_Logger { */ public function __construct() { - $this->stream = new Rop_Log_Handler( 'rop_logs' ); + $this->stream = new Rop_Log_Handler( $this->log_namespace ); } @@ -230,4 +238,23 @@ public function is_status_error_necessary( $logs = array() ) { } + /** + * Utility method to cleanup authenticated services. + * + * @access public + * + * @param int $cleanup_log_count Cleanup the log count. + * @return array + */ + public function cleanup_logs( $cleanup_log_count = 1000 ) { + $logs = $this->stream->get_logs(); + + if ( count( $logs ) > $cleanup_log_count ) { + $logs = array_slice( $logs, 0, $cleanup_log_count ); + + update_option( $this->log_namespace, array_reverse( $logs ), false ); + } + + return $logs; + } } diff --git a/includes/admin/class-rop-rest-api.php b/includes/admin/class-rop-rest-api.php index e9d118921..85dac17c2 100644 --- a/includes/admin/class-rop-rest-api.php +++ b/includes/admin/class-rop-rest-api.php @@ -1643,15 +1643,15 @@ private function add_account_bluesky( $data ) { } /** - * API method called to cleanup services. + * API method called to cleanup logs. * * @access private * @return array */ - public function cleanup_accounts() { - $model = new Rop_Services_Model(); + private function cleanup_logs() { + $model = new Rop_Logger(); $this->response->set_code( '200' ) - ->set_data( $model->cleanup_accounts() ); + ->set_data( $model->cleanup_logs() ); return $this->response->to_array(); } diff --git a/includes/admin/models/class-rop-services-model.php b/includes/admin/models/class-rop-services-model.php index a02016689..2c589557a 100644 --- a/includes/admin/models/class-rop-services-model.php +++ b/includes/admin/models/class-rop-services-model.php @@ -37,14 +37,6 @@ class Rop_Services_Model extends Rop_Model_Abstract { */ private $accounts_namespace = 'active_accounts'; - /** - * Cleanup account count. - * - * @access private - * @var int $cleanup_account_count - */ - private $cleanup_account_count = 1000; - /** * Utility method to clear authenticated services. * @@ -526,21 +518,4 @@ public function find_account( $account_id ) { return false; } - - /** - * Utility method to cleanup authenticated services. - * - * @access public - * @return array - */ - public function cleanup_accounts() { - $services = $this->get( $this->services_namespace ); - - if ( count( $services ) > $this->cleanup_account_count ) { - $services = array_slice( $services, -( $this->cleanup_account_count ), null, true ); - $this->set( $this->services_namespace, $services ); - } - - return $services; - } } diff --git a/includes/class-rop-i18n.php b/includes/class-rop-i18n.php index 74323f095..1ce36331b 100644 --- a/includes/class-rop-i18n.php +++ b/includes/class-rop-i18n.php @@ -139,10 +139,6 @@ public static function get_labels( $key = '' ) { 'upsell_bz_service_body' => __( 'We\'re sorry, %1$s is not available on your plan. Please upgrade to the business plan to unlock all these features and get more traffic.', 'tweet-old-post' ), 'search_account' => __( 'Search account', 'tweet-old-post' ), 'no_account_found' => __( 'No account found for search', 'tweet-old-post' ), - 'cleanup_cta' => __( 'Cleanup accounts', 'tweet-old-post' ), - 'cleanup_title' => __( 'Clean Up Accounts', 'tweet-old-post' ), - 'cleanup_description' => __( 'This will remove older account records and keep only the most recent 1,000 accounts. This helps improve performance and reduce stored data.', 'tweet-old-post' ), - 'cleanup_now' => __( 'Cleanup now', 'tweet-old-post' ), ), 'settings' => array( 'yes_text' => __( 'Yes', 'tweet-old-post' ), @@ -363,6 +359,13 @@ public static function get_labels( $key = '' ) { 'clear_btn' => __( 'Clear logs', 'tweet-old-post' ), 'no_logs' => __( 'No recent logs!', 'tweet-old-post' ), 'export_btn' => __( 'Export logs', 'tweet-old-post' ), + 'cleanup' => array( + 'cta' => __( 'Cleanup logs', 'tweet-old-post' ), + 'title' => __( 'Cleanup logs', 'tweet-old-post' ), + 'description' => __( 'This will remove older logs and keep only the most recent 1,000 logs. This helps improve performance and reduce stored data.', 'tweet-old-post' ), + 'btn' => __( 'Cleanup now', 'tweet-old-post' ), + ) + ), 'general' => array( 'plugin_name' => __( 'Revive Social', 'tweet-old-post' ), diff --git a/vue/src/models/rop_store.js b/vue/src/models/rop_store.js index 81ff218b7..1d7b47486 100644 --- a/vue/src/models/rop_store.js +++ b/vue/src/models/rop_store.js @@ -270,8 +270,9 @@ export default new Vuex.Store({ case 'toggle_tracking': break - case 'cleanup_accounts': - state.authenticatedServices = stateData; + case 'cleanup_logs': + state.page.logs = stateData; + state.cron_status.logs_number = stateData.length || 0; break; default: Vue.$log.error('No state request for ', requestName); diff --git a/vue/src/vue-elements/accounts-tab-panel.vue b/vue/src/vue-elements/accounts-tab-panel.vue index 8eb00b265..858351947 100644 --- a/vue/src/vue-elements/accounts-tab-panel.vue +++ b/vue/src/vue-elements/accounts-tab-panel.vue @@ -89,20 +89,6 @@
-
- @@ -183,7 +143,6 @@ upsell_link: ropApiSettings.upsell_link, pro_installed: ropApiSettings.pro_installed, postTimeout: '', - cleanupModal: false, } }, computed: { @@ -231,11 +190,6 @@ hasActiveAccountsLimitation: function () { return !this.pro_installed && this.accountsCount >= 2 && this.checkLicense ; }, - cleanupModalClass: function () { - return { - 'active': this.cleanupModal === true - } - }, }, mounted: function () { if (0 === this.is_preloading) { @@ -274,33 +228,6 @@ Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) }) }, - openCleanupModal: function() { - this.cleanupModal = true; - }, - closeCleanupModal: function() { - this.cleanupModal = false; - }, - cleanupAccount: function() { - if (this.is_loading) { - this.$log.warn('Request in progress...Bail'); - return; - } - this.is_loading = true; - this.$store.dispatch('fetchAJAXPromise', { - req: 'cleanup_accounts', - data: {} - }).then(response => { - this.is_loading = false; - this.cleanupModal = false; - if (this.$parent.start_status === true) { - // Stop sharing process if enabled. - this.$parent.togglePosting(); - } - }, error => { - this.is_loading = false; - Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) - }) - }, filteredAccounts: function(accounts) { const result = {}; const query = this.searchAccount?.toLowerCase() || ''; @@ -346,31 +273,6 @@ margin-bottom: 15px; } - #rop_core .rop-cleanup-modal .modal-container{ - max-width: 500px; - padding: 25px; - - .modal-title, .modal-footer{ - text-align: center; - } - .btn-success{ - border:none; - background-color:#00a32a; - color: #fff; - padding: 0.5rem 1rem; - height: auto; - display: inline; - } - .btn-success:hover{ - background-color:#009528; - } - .modal-body{ - font-size: 0.7rem; - margin: 10px 30px; - padding: 0px; - } - } - @media ( max-width: 600px ) { #rop_core .panel-body .text-gray { margin-bottom: 10px; diff --git a/vue/src/vue-elements/logs-tab-panel.vue b/vue/src/vue-elements/logs-tab-panel.vue index 2f8cd1de9..720898bb9 100644 --- a/vue/src/vue-elements/logs-tab-panel.vue +++ b/vue/src/vue-elements/logs-tab-panel.vue @@ -29,6 +29,21 @@ /> {{ labels.clear_btn }} +
@@ -70,6 +85,32 @@
+ @@ -86,6 +127,7 @@ is_loading: false, labels: this.$store.state.labels.logs, upsell_link: ropApiSettings.upsell_link, + cleanupModal: false, } }, computed: { @@ -95,6 +137,11 @@ logs_no: function () { return this.$store.state.cron_status.logs_number; }, + cleanupModalClass: function() { + return { + 'active': true === this.cleanupModal + } + } }, watch: { logs_no: function () { @@ -153,8 +200,34 @@ document.body.appendChild(element); element.click(); document.body.removeChild(element); - } - + }, + openCleanupModal() { + this.cleanupModal = true; + }, + closeCleanupModal() { + this.cleanupModal = false; + }, + cleanupLogs: function() { + if (this.is_loading) { + this.$log.warn('Request in progress...Bail'); + return; + } + this.is_loading = true; + this.$store.dispatch('fetchAJAXPromise', { + req: 'cleanup_logs', + data: {} + }).then(response => { + this.is_loading = false; + this.cleanupModal = false; + if (this.$parent.start_status === true) { + // Stop sharing process if enabled. + this.$parent.togglePosting(); + } + }, error => { + this.is_loading = false; + Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) + }) + }, }, } @@ -208,4 +281,27 @@ background-color: #FBE8E8; } } + #rop_core .rop-cleanup-modal .modal-container{ + max-width: 500px; + padding: 25px; + .modal-title, .modal-footer{ + text-align: center; + } + .btn-success{ + border:none; + background-color:#00a32a; + color: #fff; + padding: 0.5rem 1rem; + height: auto; + display: inline; + } + .btn-success:hover{ + background-color:#009528; + } + .modal-body{ + font-size: 0.7rem; + margin: 10px 30px; + padding: 0px; + } + } From 9253d5d48e59f5eb60648ead0ceb3e2f51f254f3 Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Tue, 13 Jan 2026 17:52:36 +0530 Subject: [PATCH 3/4] fix: phpcs --- includes/class-rop-i18n.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/includes/class-rop-i18n.php b/includes/class-rop-i18n.php index 1ce36331b..be8ac60b2 100644 --- a/includes/class-rop-i18n.php +++ b/includes/class-rop-i18n.php @@ -364,8 +364,7 @@ public static function get_labels( $key = '' ) { 'title' => __( 'Cleanup logs', 'tweet-old-post' ), 'description' => __( 'This will remove older logs and keep only the most recent 1,000 logs. This helps improve performance and reduce stored data.', 'tweet-old-post' ), 'btn' => __( 'Cleanup now', 'tweet-old-post' ), - ) - + ), ), 'general' => array( 'plugin_name' => __( 'Revive Social', 'tweet-old-post' ), From c90f11a245ea71d483e2211bb61aa97a0261bc2a Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Fri, 16 Jan 2026 11:04:01 +0530 Subject: [PATCH 4/4] fix: formatting --- vue/src/vue-elements/logs-tab-panel.vue | 120 ++++++++++++------------ 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/vue/src/vue-elements/logs-tab-panel.vue b/vue/src/vue-elements/logs-tab-panel.vue index 720898bb9..665cc8a1f 100644 --- a/vue/src/vue-elements/logs-tab-panel.vue +++ b/vue/src/vue-elements/logs-tab-panel.vue @@ -105,9 +105,11 @@ @@ -127,7 +129,7 @@ is_loading: false, labels: this.$store.state.labels.logs, upsell_link: ropApiSettings.upsell_link, - cleanupModal: false, + cleanupModal: false, } }, computed: { @@ -137,11 +139,11 @@ logs_no: function () { return this.$store.state.cron_status.logs_number; }, - cleanupModalClass: function() { - return { - 'active': true === this.cleanupModal - } - } + cleanupModalClass: function() { + return { + 'active': true === this.cleanupModal + } + } }, watch: { logs_no: function () { @@ -201,33 +203,33 @@ element.click(); document.body.removeChild(element); }, - openCleanupModal() { - this.cleanupModal = true; - }, - closeCleanupModal() { - this.cleanupModal = false; - }, - cleanupLogs: function() { - if (this.is_loading) { - this.$log.warn('Request in progress...Bail'); - return; - } - this.is_loading = true; - this.$store.dispatch('fetchAJAXPromise', { - req: 'cleanup_logs', - data: {} - }).then(response => { - this.is_loading = false; - this.cleanupModal = false; - if (this.$parent.start_status === true) { - // Stop sharing process if enabled. - this.$parent.togglePosting(); - } - }, error => { - this.is_loading = false; - Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) - }) - }, + openCleanupModal() { + this.cleanupModal = true; + }, + closeCleanupModal() { + this.cleanupModal = false; + }, + cleanupLogs: function() { + if (this.is_loading) { + this.$log.warn('Request in progress...Bail'); + return; + } + this.is_loading = true; + this.$store.dispatch('fetchAJAXPromise', { + req: 'cleanup_logs', + data: {} + }).then(response => { + this.is_loading = false; + this.cleanupModal = false; + if (this.$parent.start_status === true) { + // Stop sharing process if enabled. + this.$parent.togglePosting(); + } + }, error => { + this.is_loading = false; + Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) + }) + }, }, } @@ -281,27 +283,27 @@ background-color: #FBE8E8; } } - #rop_core .rop-cleanup-modal .modal-container{ - max-width: 500px; - padding: 25px; - .modal-title, .modal-footer{ - text-align: center; - } - .btn-success{ - border:none; - background-color:#00a32a; - color: #fff; - padding: 0.5rem 1rem; - height: auto; - display: inline; - } - .btn-success:hover{ - background-color:#009528; - } - .modal-body{ - font-size: 0.7rem; - margin: 10px 30px; - padding: 0px; - } - } + #rop_core .rop-cleanup-modal .modal-container{ + max-width: 500px; + padding: 25px; + .modal-title, .modal-footer{ + text-align: center; + } + .btn-success{ + border:none; + background-color:#00a32a; + color: #fff; + padding: 0.5rem 1rem; + height: auto; + display: inline; + } + .btn-success:hover{ + background-color:#009528; + } + .modal-body{ + font-size: 0.7rem; + margin: 10px 30px; + padding: 0px; + } + }