-
First, I take no responsibility for any damages to projects resulting from these detailed suggestions.
BACK UP, BACK UP!!!! THEN TRY these steps.
I would not run that script on production as-is. It is very likely to (a) miss the real UNA data paths for timeline media, (b) leave orphans, and (c) potentially delete files that are not exclusively owned by the timeline event.
Below is a structured review and a safer pattern.
Key issues in the current script
1) Wrong tables for UNA 14 Timeline/comments/notifications (high probability)
From your own schema list earlier, you have
bx_timeline_comments, notbx_timeline_cmts. UNA’s comments system is often abstracted and not always stored where people expect (there’ssys_cmts_*plus per-module comment tables depending on module/version). If you delete from the wrong table, you either:- delete nothing (so media stays), or
- delete partial state (orphans elsewhere).
Same concern for notifications: your DB list shows
bx_notifications_*, notbx_ntfs_*. So this block will likely be wrong on your install.2) Deleting from
bx_filesis almost certainly not deleting the physical mediaUNA media is typically stored via Storage objects (
sys_files,sys_images,sys_storage_*, transcoders, ghosts/deletions queues). The “Timeline post has images/videos” usually means:- timeline event references storage IDs (and transcoder outputs), not a “bx_files module row” you can safely delete.
- deleting a row from a module table does not guarantee storage cleanup (and can actually break cleanup).
So even if your SQL deletes some module mapping rows, disk usage likely won’t drop as expected.
3) Ownership checks are insufficient / can be wrong
DELETE FROM bx_files WHERE id IN (...) AND owner_id=...assumes:- those file rows are unique to that timeline post,
- and owned by that event owner.
- Both assumptions are risky. Reused media, shared attachments, or cross-module references can exist.
4) Bypasses UNA’s internal delete hooks
UNA deletion typically triggers:
- storage delete / garbage collection
- transcoders cleanup
- votes, reactions, reports, views, metas
- alerts/events for other modules
- Your script deletes “a few obvious tables” but does not run those hooks. That’s the main reason orphaned data accumulates.
5)
escape()use is not what you thinkYou cast to
(int), which is good. But then you do$db->escape($eventId)in numeric contexts. Many escape implementations return quoted strings. It often “works,” but it’s not guaranteed and it can produce odd SQL. For ints, use ints.6) Operational risks
- No batching/limits: could run for a long time, lock tables, and spike load.
- Lock file TTL is 300s; a real run could exceed that and allow overlap if cron triggers again.
- Log path
/var/log/...will often fail on shared hosting unless permissions are configured.
What you should do instead (safe UNA-native approach)
Preferred approach: delete via the Timeline module / service API
The safe pattern is:
- Bootstrap UNA (
inc/header.inc.php) - Load the Timeline module instance
- For each event ID, call the module’s delete method (or service) that UNA uses internally.
This ensures:
- storage objects are notified,
- dependent system tables are cleaned,
- transcoders/ghosts/deletions are handled correctly.
Because I cannot execute your server code, I’ll describe the pattern you should use:
- Use module instance:
BxDolModule::getInstance('bx_timeline') - Then call the module’s delete entry/event method (often something like
deleteEvent(),deleteEntity(), or service wrapper).
If you open
modules/boonex/timeline/classes/BxTimelineModule.phpand search fordeletemethods, you’ll typically find the correct callable that UNA expects you to use (and Studio/admin UI uses).Alternative approach: “soft delete” then let storage GC do its job
If you’re nervous about hard deletes:
- Mark old posts as hidden/archived (status update)
- Run UNA maintenance / storage cleanup to purge unreferenced files
This reduces risk of accidental data loss and still gets you disk back once garbage collection runs.
Concrete improvements you can apply immediately
A) Start with a “list-only” dry run that does not touch dependent tables
Your current dry-run is already querying the wrong comment table and wrong file linkage table. First, confirm the real schema relationships by querying
bx_timeline_eventsto see how media is referenced.Run this in phpMyAdmin:
SELECT id, owner_id, type, content, date FROM bx_timeline_events WHERE type='post' ORDER BY date DESC LIMIT 5;Look at the
contentcolumn. If it contains serialized/JSON references to storage objects (common), you must use the module delete routine, not manual deletes.B) Add batching and time-boxing
Delete in batches (e.g., 200 events per run), then exit cleanly. This avoids timeouts and reduces lock/load risk.
C) Use a lock that cannot expire mid-run
Example: create lock file, write PID + timestamp, and only release at end. Don’t rely on a short TTL.
D) Log to a writable path
Use something like:
BX_DIRECTORY_PATH_LOGS . 'timeline_cleanup.log'(if available), or__DIR__ . '/timeline_cleanup.log'inside your UNA root (temporarily)
A safer skeleton (still requires you to map the correct delete call)
This is what a production-safe structure looks like, conceptually:
require_once __DIR__ . '/inc/header.inc.php'; $daysOld = 60; $dryRun = true; $batch = 200; $cutoff = time() - (86400 * $daysOld); $db = BxDolDb::getInstance(); $eventIds = $db->getColumn(" SELECT `id` FROM `bx_timeline_events` WHERE `type`='post' AND `date` < :cutoff AND `status` <> 'hidden' ORDER BY `date` ASC LIMIT :batch ", ['cutoff' => $cutoff, 'batch' => $batch]); $timeline = BxDolModule::getInstance('bx_timeline'); if (!$timeline) die('Timeline module not found'); foreach ($eventIds as $eventId) { $eventId = (int)$eventId; if ($dryRun) { // log "would delete" continue; } // Replace this with the ACTUAL timeline deletion call from your install: // e.g. $timeline->deleteEvent($eventId); // or BxDolService::call('bx_timeline', 'delete_event', [$eventId]); }Important: I’m intentionally not inventing the final call name. You must use the method/service your installed Timeline module provides, because that’s what guarantees storage cleanup.
What I need from you to give the exact final delete call
Paste the relevant portion of one of these files (just the delete-related methods, ~50–150 lines is enough):
modules/boonex/timeline/classes/BxTimelineModule.php(search forfunction delete)modules/boonex/timeline/classes/BxTimelineDb.php(search fordelete/remove)- Any service definitions for timeline (search in the module for
servicemethods)
With that snippet, I can tell you exactly which method/service to call and how to structure the script so it:
- deletes the event,
- deletes attached media via Storage,
- triggers required cleanup across comments/reactions/views/reports,
- and doesn’t accidentally delete shared files.
One more operational note
Because you previously had a lot of collation inconsistency and PHP notices, I’d also recommend:
- Run this cleanup only after your DB collation normalization is complete.
- run it during low traffic,
- and keep
$dryRun=trueuntil you’ve validated that disk usage decreases via UNA’s storage tables/paths.
If you paste the delete-method snippet from
BxTimelineModule.phI’ll produce a production-ready script that uses the correct UNA API and a safe batch/lock/log design.