load_dependencies(); $this->init_hooks(); } /** * Load required files */ private function load_dependencies() { // Core classes require_once MLS_PLUGIN_DIR . 'includes/class-mls-db.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-options.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-logger.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-rate-limiter.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-api-client.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-sync-engine.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-media-handler.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-image-endpoint.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-query.php'; // Activation/Deactivation require_once MLS_PLUGIN_DIR . 'includes/class-mls-activator.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-deactivator.php'; // Admin if (is_admin()) { require_once MLS_PLUGIN_DIR . 'admin/class-mls-admin.php'; } // WP-CLI if (defined('WP_CLI') && WP_CLI) { require_once MLS_PLUGIN_DIR . 'cli/class-mls-cli.php'; } } /** * Initialize hooks */ private function init_hooks() { // Activation/Deactivation hooks register_activation_hook(MLS_PLUGIN_FILE, array('MLS_Activator', 'activate')); register_deactivation_hook(MLS_PLUGIN_FILE, array('MLS_Deactivator', 'deactivate')); // Initialize components after plugins loaded add_action('plugins_loaded', array($this, 'init_components')); // Check for database updates add_action('plugins_loaded', array($this, 'check_db_updates')); } /** * Initialize plugin components */ public function init_components() { $this->db = new MLS_DB(); $this->options = new MLS_Options(); $this->logger = new MLS_Logger($this->db); $this->rate_limiter = new MLS_Rate_Limiter($this->db); $this->api_client = new MLS_API_Client($this->options, $this->rate_limiter, $this->logger); $this->media_handler = new MLS_Media_Handler($this->db, $this->logger); $this->image_endpoint = new MLS_Image_Endpoint($this->media_handler, $this->logger); $this->image_endpoint->init(); $this->sync_engine = new MLS_Sync_Engine( $this->db, $this->api_client, $this->media_handler, $this->logger ); $this->query = new MLS_Query($this->db); // Initialize admin if (is_admin()) { new MLS_Admin($this); } // Initialize CLI if (defined('WP_CLI') && WP_CLI) { MLS_CLI::register($this); } } /** * Check and run database updates */ public function check_db_updates() { $current_version = get_option('mls_db_version', '0'); if (version_compare($current_version, MLS_DB_VERSION, '<')) { MLS_Activator::create_tables(); update_option('mls_db_version', MLS_DB_VERSION); } } /** * Get DB instance */ public function get_db() { return $this->db; } /** * Get Options instance */ public function get_options() { return $this->options; } /** * Get Logger instance */ public function get_logger() { return $this->logger; } /** * Get Rate Limiter instance */ public function get_rate_limiter() { return $this->rate_limiter; } /** * Get API Client instance */ public function get_api_client() { return $this->api_client; } /** * Get Sync Engine instance */ public function get_sync_engine() { return $this->sync_engine; } /** * Get Media Handler instance */ public function get_media_handler() { return $this->media_handler; } /** * Get Image Endpoint instance */ public function get_image_endpoint() { return $this->image_endpoint; } /** * Get Query instance */ public function get_query() { return $this->query; } } /** * Initialize the plugin */ function mls_plugin() { return MLS_Plugin::get_instance(); } // Start the plugin add_action('plugins_loaded', 'mls_plugin', 0); /** * Global helper functions for themes/plugins */ /** * Get MLS properties * * @param array $args Query arguments * @return array Array of property objects */ function mls_get_properties($args = array()) { $plugin = mls_plugin(); if (!$plugin->get_query()) { return array(); } return $plugin->get_query()->get_properties($args); } /** * Get a single MLS property * * @param string $identifier Listing key or MLS ID * @return object|null Property object or null */ function mls_get_property($identifier) { $plugin = mls_plugin(); if (!$plugin->get_query()) { return null; } return $plugin->get_query()->get_property($identifier); } /** * Get media for a listing * * @param string $listing_key The listing key * @return array Array of media objects */ function mls_get_property_media($listing_key) { $plugin = mls_plugin(); if (!$plugin->get_query()) { return array(); } return $plugin->get_query()->get_property_media($listing_key); } /** * Get primary image URL for a listing (on-demand fetching) * * Images are fetched from MLS Grid and cached locally on first request. * Per MLS Grid rules, images must be served from our own server. * * @param string $listing_key The listing key * @param bool $fetch_if_missing Whether to fetch from MLS Grid if not cached (default: true) * @return string|null Image URL or null */ function mls_get_property_image($listing_key, $fetch_if_missing = true) { $plugin = mls_plugin(); if (!$plugin->get_media_handler()) { return null; } return $plugin->get_media_handler()->get_primary_image($listing_key, $fetch_if_missing); } /** * Get distinct cities with listings * * @param string|null $status Optional status filter * @return array Array of city names */ function mls_get_cities($status = null) { $plugin = mls_plugin(); if (!$plugin->get_query()) { return array(); } return $plugin->get_query()->get_distinct_cities($status); } /** * Check if MLS data is available * * @return bool True if synced data exists */ function mls_is_available() { $plugin = mls_plugin(); if (!$plugin->get_query()) { return false; } return $plugin->get_query()->has_data(); } /** * Get property count * * @param array $args Optional filter arguments * @return int Property count */ function mls_get_property_count($args = array()) { $plugin = mls_plugin(); if (!$plugin->get_query()) { return 0; } return $plugin->get_query()->get_count($args); } /** * Get all images for a listing (on-demand fetching) * * Returns all media records with local_url populated where cached. * Can optionally fetch first N uncached images on-demand. * * @param string $listing_key The listing key * @param int $fetch_limit Max images to fetch on-demand (default: 1, 0 = none) * @return array Array of media objects */ function mls_get_property_images($listing_key, $fetch_limit = 1) { $plugin = mls_plugin(); if (!$plugin->get_media_handler()) { return array(); } return $plugin->get_media_handler()->get_listing_images($listing_key, $fetch_limit); } /** * Get media cache statistics * * @return array Stats with total_media, cached, uncached counts */ function mls_get_cache_stats() { $plugin = mls_plugin(); if (!$plugin->get_media_handler()) { return array('total_media' => 0, 'cached' => 0, 'uncached' => 0); } return $plugin->get_media_handler()->get_cache_stats(); } /** * Get WebP thumbnail URL for a listing image * * Returns a URL to the WebP thumbnail endpoint which will: * - Fetch the image from MLS Grid if not cached * - Convert to WebP format using ImageMagick * - Resize to requested dimension (800px thumb or 1800px full) * - Cache the result for future requests * * @param string $listing_key The listing key * @param int $index Image index (1-based, default: 1 for primary image) * @param string $size 'thumb' (800px) or 'full' (1800px), default: 'thumb' * @return string Image URL */ function mls_get_image_url($listing_key, $index = 1, $size = 'thumb') { return MLS_Image_Endpoint::get_url($listing_key, $index, $size); }