| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!defined('ABSPATH')) {
|
| exit;
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!defined('PN_FCOM_DELETE_HOOK')) {
|
| define('PN_FCOM_DELETE_HOOK', 'pn_fcom_delete_space_feed_after_delay');
|
| }
|
|
|
| if (!defined('PN_FCOM_DELETE_META_KEY')) {
|
| define('PN_FCOM_DELETE_META_KEY', '_pn_fcom_delete_scheduled');
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_target_space_slug')) {
|
| function pn_fcom_target_space_slug() {
|
| return sanitize_title((string) apply_filters('pn_fcom_target_space_slug', 'drug-shortages'));
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_delete_delay_seconds')) {
|
| function pn_fcom_delete_delay_seconds() {
|
| $seconds = (int) apply_filters('pn_fcom_delete_delay_seconds', 30);
|
| return max(5, $seconds);
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_enable_delete')) {
|
| function pn_fcom_enable_delete() {
|
| return (bool) apply_filters('pn_fcom_enable_delete', true);
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_log')) {
|
| function pn_fcom_log($message, array $context = array()) {
|
| $enabled = (bool) apply_filters('pn_fcom_enable_debug_log', false);
|
|
|
| if (!$enabled) {
|
| return;
|
| }
|
|
|
| $line = '[PN_FCOM] ' . $message;
|
|
|
| if (!empty($context)) {
|
| $line .= ' | ' . wp_json_encode($context);
|
| }
|
|
|
| error_log($line);
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_get_feed_value')) {
|
| function pn_fcom_get_feed_value($feed, $key, $default = null) {
|
| if (is_object($feed) && isset($feed->{$key})) {
|
| return $feed->{$key};
|
| }
|
|
|
| if (is_array($feed) && array_key_exists($key, $feed)) {
|
| return $feed[$key];
|
| }
|
|
|
| return $default;
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_is_valid_feed_payload')) {
|
| function pn_fcom_is_valid_feed_payload($feed) {
|
| return !empty($feed) && (is_object($feed) || is_array($feed));
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_get_feed_id')) {
|
| function pn_fcom_get_feed_id($feed) {
|
| return (int) pn_fcom_get_feed_value($feed, 'id', 0);
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_get_feed_space_id')) {
|
| function pn_fcom_get_feed_space_id($feed) {
|
| return (int) pn_fcom_get_feed_value($feed, 'space_id', 0);
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_get_feed_type')) {
|
| function pn_fcom_get_feed_type($feed) {
|
| return (string) pn_fcom_get_feed_value($feed, 'feed_type', '');
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_feed_exists')) {
|
| function pn_fcom_feed_exists($feed_id) {
|
| $feed_id = (int) $feed_id;
|
|
|
| if ($feed_id <= 0) {
|
| return false;
|
| }
|
|
|
| if (!class_exists('\FluentCommunity\App\Models\Feed')) {
|
| return false;
|
| }
|
|
|
| try {
|
| $feed_model_class = '\FluentCommunity\App\Models\Feed';
|
| $feed = $feed_model_class::find($feed_id);
|
|
|
| return !empty($feed);
|
| } catch (\Throwable $e) {
|
| pn_fcom_log('Feed exists check failed.', array(
|
| 'feed_id' => $feed_id,
|
| 'error' => $e->getMessage(),
|
| ));
|
|
|
| return false;
|
| }
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_is_target_space_feed')) {
|
| function pn_fcom_is_target_space_feed($feed) {
|
| $target_space_id = pn_fcom_get_target_space_id();
|
|
|
| if ($target_space_id <= 0) {
|
| return false;
|
| }
|
|
|
| $space_id = pn_fcom_get_feed_space_id($feed);
|
|
|
| return $space_id > 0 && $space_id === $target_space_id;
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_should_schedule_feed_deletion')) {
|
| function pn_fcom_should_schedule_feed_deletion($feed) {
|
| if (!pn_fcom_is_valid_feed_payload($feed)) {
|
| pn_fcom_log('Invalid feed payload on create.');
|
| return false;
|
| }
|
|
|
| $feed_id = pn_fcom_get_feed_id($feed);
|
| $space_id = pn_fcom_get_feed_space_id($feed);
|
| $feed_type = pn_fcom_get_feed_type($feed);
|
|
|
| if ($feed_id <= 0 || $space_id <= 0) {
|
| pn_fcom_log('Feed payload missing id or space_id.', array(
|
| 'feed_id' => $feed_id,
|
| 'space_id' => $space_id,
|
| 'feed_type' => $feed_type,
|
| ));
|
| return false;
|
| }
|
|
|
| if (!pn_fcom_is_target_space_feed($feed)) {
|
| pn_fcom_log('Feed ignored because it is not in target space.', array(
|
| 'feed_id' => $feed_id,
|
| 'space_id' => $space_id,
|
| 'feed_type' => $feed_type,
|
| 'target_id' => pn_fcom_get_target_space_id(),
|
| ));
|
| return false;
|
| }
|
|
|
| if (!pn_fcom_feed_exists($feed_id)) {
|
| pn_fcom_log('Feed does not exist at schedule time.', array(
|
| 'feed_id' => $feed_id,
|
| ));
|
| return false;
|
| }
|
|
|
| return true;
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_get_schedule_option_key')) {
|
| function pn_fcom_get_schedule_option_key($feed_id) {
|
| return PN_FCOM_DELETE_META_KEY . '_' . (int) $feed_id;
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_mark_feed_scheduled')) {
|
| function pn_fcom_mark_feed_scheduled($feed_id, $timestamp) {
|
| $feed_id = (int) $feed_id;
|
| $timestamp = (int) $timestamp;
|
| $option_key = pn_fcom_get_schedule_option_key($feed_id);
|
|
|
| update_option($option_key, $timestamp, false);
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_get_feed_scheduled_timestamp')) {
|
| function pn_fcom_get_feed_scheduled_timestamp($feed_id) {
|
| $feed_id = (int) $feed_id;
|
| $option_key = pn_fcom_get_schedule_option_key($feed_id);
|
|
|
| return (int) get_option($option_key, 0);
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_unmark_feed_scheduled')) {
|
| function pn_fcom_unmark_feed_scheduled($feed_id) {
|
| $feed_id = (int) $feed_id;
|
| $option_key = pn_fcom_get_schedule_option_key($feed_id);
|
|
|
| delete_option($option_key);
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_get_target_space_id')) {
|
| function pn_fcom_get_target_space_id() {
|
| static $cache = array();
|
|
|
| $slug = pn_fcom_target_space_slug();
|
|
|
| if (!$slug) {
|
| return 0;
|
| }
|
|
|
| if (isset($cache[$slug])) {
|
| return (int) $cache[$slug];
|
| }
|
|
|
| $space_id = 0;
|
|
|
| if (class_exists('\FluentCommunity\App\Models\Space')) {
|
| try {
|
| $space_model_class = '\FluentCommunity\App\Models\Space';
|
|
|
| $space_id = (int) $space_model_class::query()
|
| ->where('slug', $slug)
|
| ->value('id');
|
| } catch (\Throwable $e) {
|
| pn_fcom_log('Space model lookup failed, trying SQL fallback.', array(
|
| 'slug' => $slug,
|
| 'error' => $e->getMessage(),
|
| ));
|
| }
|
| }
|
|
|
| if ($space_id <= 0) {
|
| global $wpdb;
|
|
|
| $table = $wpdb->prefix . 'fcom_spaces';
|
|
|
| $table_exists = $wpdb->get_var(
|
| $wpdb->prepare('SHOW TABLES LIKE %s', $table)
|
| );
|
|
|
| if ($table_exists === $table) {
|
| $space_id = (int) $wpdb->get_var(
|
| $wpdb->prepare(
|
| "SELECT id FROM {$table} WHERE slug = %s LIMIT 1",
|
| $slug
|
| )
|
| );
|
| } else {
|
| pn_fcom_log('FluentCommunity spaces table not found.', array(
|
| 'table' => $table,
|
| ));
|
| }
|
| }
|
|
|
| $cache[$slug] = $space_id > 0 ? $space_id : 0;
|
|
|
| return (int) $cache[$slug];
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_schedule_feed_deletion')) {
|
| function pn_fcom_schedule_feed_deletion($feed_id) {
|
| $feed_id = (int) $feed_id;
|
|
|
| if ($feed_id <= 0) {
|
| return false;
|
| }
|
|
|
| $args = array($feed_id);
|
|
|
| $existing = wp_next_scheduled(PN_FCOM_DELETE_HOOK, $args);
|
|
|
| if ($existing) {
|
| pn_fcom_log('Delete already scheduled.', array(
|
| 'feed_id' => $feed_id,
|
| 'timestamp' => (int) $existing,
|
| ));
|
| return true;
|
| }
|
|
|
| $timestamp = current_time('timestamp', true) + pn_fcom_delete_delay_seconds();
|
|
|
| $scheduled = wp_schedule_single_event(
|
| $timestamp,
|
| PN_FCOM_DELETE_HOOK,
|
| $args
|
| );
|
|
|
| if ($scheduled) {
|
| pn_fcom_mark_feed_scheduled($feed_id, $timestamp);
|
|
|
| pn_fcom_log('Delete scheduled.', array(
|
| 'feed_id' => $feed_id,
|
| 'timestamp' => $timestamp,
|
| 'delay' => pn_fcom_delete_delay_seconds(),
|
| ));
|
| return true;
|
| }
|
|
|
| pn_fcom_log('Failed to schedule delete.', array(
|
| 'feed_id' => $feed_id,
|
| ));
|
|
|
| return false;
|
| }
|
| }
|
|
|
| if (!function_exists('pn_fcom_unschedule_feed_deletion')) {
|
| function pn_fcom_unschedule_feed_deletion($feed_id) {
|
| $feed_id = (int) $feed_id;
|
|
|
| if ($feed_id <= 0) {
|
| return 0;
|
| }
|
|
|
| $args = array($feed_id);
|
| $count = 0;
|
|
|
| while ($timestamp = wp_next_scheduled(PN_FCOM_DELETE_HOOK, $args)) {
|
| $unscheduled = wp_unschedule_event($timestamp, PN_FCOM_DELETE_HOOK, $args);
|
|
|
| if (!$unscheduled) {
|
| break;
|
| }
|
|
|
| $count++;
|
| }
|
|
|
| pn_fcom_unmark_feed_scheduled($feed_id);
|
|
|
| pn_fcom_log('Delete unscheduled.', array(
|
| 'feed_id' => $feed_id,
|
| 'count' => $count,
|
| ));
|
|
|
| return $count;
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_schedule_space_feed_deletion')) {
|
| function pn_fcom_schedule_space_feed_deletion($feed) {
|
| if (!pn_fcom_enable_delete()) {
|
| pn_fcom_log('Deletion disabled by filter.');
|
| return;
|
| }
|
|
|
| if (!pn_fcom_should_schedule_feed_deletion($feed)) {
|
| return;
|
| }
|
|
|
| pn_fcom_schedule_feed_deletion(pn_fcom_get_feed_id($feed));
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
| add_action('fluent_community/space_feed/created', 'pn_fcom_schedule_space_feed_deletion', 10, 1);
|
| add_action('fluent_community/feed/created', 'pn_fcom_schedule_space_feed_deletion', 10, 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_delete_scheduled_space_feed')) {
|
| function pn_fcom_delete_scheduled_space_feed($feed_id) {
|
| $feed_id = (int) $feed_id;
|
|
|
| if ($feed_id <= 0) {
|
| return;
|
| }
|
|
|
| $scheduled_at = pn_fcom_get_feed_scheduled_timestamp($feed_id);
|
| pn_fcom_unmark_feed_scheduled($feed_id);
|
|
|
| if (!pn_fcom_enable_delete()) {
|
| pn_fcom_log('Deletion skipped because feature is disabled.', array(
|
| 'feed_id' => $feed_id,
|
| ));
|
| return;
|
| }
|
|
|
| if (!class_exists('\FluentCommunity\App\Models\Feed')) {
|
| pn_fcom_log('Feed model class not available.', array(
|
| 'feed_id' => $feed_id,
|
| ));
|
| return;
|
| }
|
|
|
| try {
|
| $feed_model_class = '\FluentCommunity\App\Models\Feed';
|
| $feed = $feed_model_class::find($feed_id);
|
|
|
| if (!$feed) {
|
| pn_fcom_log('Feed already missing. Nothing to delete.', array(
|
| 'feed_id' => $feed_id,
|
| ));
|
| return;
|
| }
|
|
|
| $target_space_id = pn_fcom_get_target_space_id();
|
|
|
| if ($target_space_id <= 0) {
|
| pn_fcom_log('Target space id not found during delete.', array(
|
| 'feed_id' => $feed_id,
|
| 'slug' => pn_fcom_target_space_slug(),
|
| ));
|
| return;
|
| }
|
|
|
| $feed_space_id = isset($feed->space_id) ? (int) $feed->space_id : 0;
|
| $feed_status = isset($feed->status) ? (string) $feed->status : '';
|
| $feed_type = isset($feed->feed_type) ? (string) $feed->feed_type : '';
|
|
|
| if ($feed_space_id !== $target_space_id) {
|
| pn_fcom_log('Safety check prevented deletion.', array(
|
| 'feed_id' => $feed_id,
|
| 'feed_space_id' => $feed_space_id,
|
| 'target_space' => $target_space_id,
|
| ));
|
| return;
|
| }
|
|
|
| pn_fcom_log('Deleting feed.', array(
|
| 'feed_id' => $feed_id,
|
| 'space_id' => $feed_space_id,
|
| 'status' => $feed_status,
|
| 'feed_type' => $feed_type,
|
| 'scheduledAt' => $scheduled_at,
|
| ));
|
|
|
| $feed->delete();
|
|
|
| pn_fcom_log('Feed deleted successfully.', array(
|
| 'feed_id' => $feed_id,
|
| ));
|
| } catch (\Throwable $e) {
|
| pn_fcom_log('Exception while deleting feed.', array(
|
| 'feed_id' => $feed_id,
|
| 'error' => $e->getMessage(),
|
| ));
|
| }
|
| }
|
| }
|
|
|
| add_action(PN_FCOM_DELETE_HOOK, 'pn_fcom_delete_scheduled_space_feed', 10, 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (!function_exists('pn_fcom_cleanup_scheduled_delete')) {
|
| function pn_fcom_cleanup_scheduled_delete($feed_id) {
|
| if (is_object($feed_id)) {
|
| $feed_id = isset($feed_id->id) ? (int) $feed_id->id : 0;
|
| } elseif (is_array($feed_id)) {
|
| $feed_id = isset($feed_id['id']) ? (int) $feed_id['id'] : 0;
|
| } else {
|
| $feed_id = (int) $feed_id;
|
| }
|
|
|
| if ($feed_id <= 0) {
|
| return;
|
| }
|
|
|
| $count = pn_fcom_unschedule_feed_deletion($feed_id);
|
|
|
| pn_fcom_log('Cleanup after manual delete.', array(
|
| 'feed_id' => $feed_id,
|
| 'count' => $count,
|
| ));
|
| }
|
| }
|
|
|
| add_action('fluent_community/feed/deleted', 'pn_fcom_cleanup_scheduled_delete', 10, 1);
|
| add_action('fluent_community/space_feed/deleted', 'pn_fcom_cleanup_scheduled_delete', 10, 1);
|
| |
| |
Comments