Snapshot: MLS sync fixes, image refresh, plugin/theme updates

MLS plugin fixes from this session:
- Fix silent insert failures: location column NOT NULL was rejecting wpdb->insert calls,
  causing ~18k new properties since Dec 2025 to be lost. Inserts now build raw SQL
  with ST_PointFromText so the spatial column is populated atomically.
- Auto-refresh expired media URLs in MLS_Media_Handler::fetch_and_cache(), guarded by
  a property-level GET_LOCK so concurrent fetches share one API refresh.
- Normalize WP_Error to null in mls_get_property_image() so callers can rely on the
  documented string|null contract.
- Support comma-separated property_type filters in MLS_Query and MLS_Cluster so the
  homepage "View All Commercial" link (?property_type=Commercial+Sale,Land,Farm)
  actually filters correctly.
- Incremental sync now looks back 10 minutes past the latest modification timestamp
  as a safety margin against missed records.
- Smart sync exits silently (info-level, not warning) when a full sync is in progress.

Operational:
- New cron: weekly full sync Sundays at 3 AM (/usr/local/bin/mls-full-sync).
- New cron: hourly 2GB cap on mls-thumbnails/ and cache/transformed-images/
  (/usr/local/bin/mls-image-cache-cap).
- Logrotate config for wp-content/debug.log (2-day retention, daily rotation,
  delaycompress).

Repo policy:
- CLAUDE.md updated with explicit "commit everything except build artifacts" policy.
- .gitignore: untrack runtime image caches and debug.log rotations.

Other modifications in this snapshot are pre-existing in-flight theme/plugin/db_content_updates work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-04-29 15:32:23 +00:00
parent 57b752f54e
commit b6df4dbb92
5385 changed files with 838580 additions and 2416 deletions
@@ -0,0 +1,191 @@
<?php
/**
* Class ActionScheduler_Action
*/
class ActionScheduler_Action {
/**
* Action's hook.
*
* @var string
*/
protected $hook = '';
/**
* Action's args.
*
* @var array<string, mixed>
*/
protected $args = array();
/**
* Action's schedule.
*
* @var ActionScheduler_Schedule
*/
protected $schedule = null;
/**
* Action's group.
*
* @var string
*/
protected $group = '';
/**
* Priorities are conceptually similar to those used for regular WordPress actions.
* Like those, a lower priority takes precedence over a higher priority and the default
* is 10.
*
* Unlike regular WordPress actions, the priority of a scheduled action is strictly an
* integer and should be kept within the bounds 0-255 (anything outside the bounds will
* be brought back into the acceptable range).
*
* @var int
*/
protected $priority = 10;
/**
* Construct.
*
* @param string $hook Action's hook.
* @param mixed[] $args Action's arguments.
* @param null|ActionScheduler_Schedule $schedule Action's schedule.
* @param string $group Action's group.
*/
public function __construct( $hook, array $args = array(), ?ActionScheduler_Schedule $schedule = null, $group = '' ) {
$schedule = empty( $schedule ) ? new ActionScheduler_NullSchedule() : $schedule;
$this->set_hook( $hook );
$this->set_schedule( $schedule );
$this->set_args( $args );
$this->set_group( $group );
}
/**
* Executes the action.
*
* If no callbacks are registered, an exception will be thrown and the action will not be
* fired. This is useful to help detect cases where the code responsible for setting up
* a scheduled action no longer exists.
*
* @throws Exception If no callbacks are registered for this action.
*/
public function execute() {
$hook = $this->get_hook();
if ( ! has_action( $hook ) ) {
throw new Exception(
sprintf(
/* translators: 1: action hook. */
__( 'Scheduled action for %1$s will not be executed as no callbacks are registered.', 'action-scheduler' ),
$hook
)
);
}
do_action_ref_array( $hook, array_values( $this->get_args() ) );
}
/**
* Set action's hook.
*
* @param string $hook Action's hook.
*/
protected function set_hook( $hook ) {
$this->hook = $hook;
}
/**
* Get action's hook.
*/
public function get_hook() {
return $this->hook;
}
/**
* Set action's schedule.
*
* @param ActionScheduler_Schedule $schedule Action's schedule.
*/
protected function set_schedule( ActionScheduler_Schedule $schedule ) {
$this->schedule = $schedule;
}
/**
* Action's schedule.
*
* @return ActionScheduler_Schedule
*/
public function get_schedule() {
return $this->schedule;
}
/**
* Set action's args.
*
* @param mixed[] $args Action's arguments.
*/
protected function set_args( array $args ) {
$this->args = $args;
}
/**
* Get action's args.
*/
public function get_args() {
return $this->args;
}
/**
* Section action's group.
*
* @param string $group Action's group.
*/
protected function set_group( $group ) {
$this->group = $group;
}
/**
* Action's group.
*
* @return string
*/
public function get_group() {
return $this->group;
}
/**
* Action has not finished.
*
* @return bool
*/
public function is_finished() {
return false;
}
/**
* Sets the priority of the action.
*
* @param int $priority Priority level (lower is higher priority). Should be in the range 0-255.
*
* @return void
*/
public function set_priority( $priority ) {
if ( $priority < 0 ) {
$priority = 0;
} elseif ( $priority > 255 ) {
$priority = 255;
}
$this->priority = (int) $priority;
}
/**
* Gets the action priority.
*
* @return int
*/
public function get_priority() {
return $this->priority;
}
}
@@ -0,0 +1,25 @@
<?php
/**
* Class ActionScheduler_CanceledAction
*
* Stored action which was canceled and therefore acts like a finished action but should always return a null schedule,
* regardless of schedule passed to its constructor.
*/
class ActionScheduler_CanceledAction extends ActionScheduler_FinishedAction {
/**
* Construct.
*
* @param string $hook Action's hook.
* @param array $args Action's arguments.
* @param null|ActionScheduler_Schedule $schedule Action's schedule.
* @param string $group Action's group.
*/
public function __construct( $hook, array $args = array(), ?ActionScheduler_Schedule $schedule = null, $group = '' ) {
parent::__construct( $hook, $args, $schedule, $group );
if ( is_null( $schedule ) ) {
$this->set_schedule( new ActionScheduler_NullSchedule() );
}
}
}
@@ -0,0 +1,21 @@
<?php
/**
* Class ActionScheduler_FinishedAction
*/
class ActionScheduler_FinishedAction extends ActionScheduler_Action {
/**
* Execute action.
*/
public function execute() {
// don't execute.
}
/**
* Get finished state.
*/
public function is_finished() {
return true;
}
}
@@ -0,0 +1,25 @@
<?php
/**
* Class ActionScheduler_NullAction
*/
class ActionScheduler_NullAction extends ActionScheduler_Action {
/**
* Construct.
*
* @param string $hook Action hook.
* @param mixed[] $args Action arguments.
* @param null|ActionScheduler_Schedule $schedule Action schedule.
*/
public function __construct( $hook = '', array $args = array(), ?ActionScheduler_Schedule $schedule = null ) {
$this->set_schedule( new ActionScheduler_NullSchedule() );
}
/**
* Execute action.
*/
public function execute() {
// don't execute.
}
}