/* Plugin Name: FAAM Core Plugin URI: https://faamprop.com Description: FAAM Property Core Functions Version: 1.3.1 Author: FAAM Property */ /* |-------------------------------------------------------------------------- | Register REST Meta |-------------------------------------------------------------------------- */ add_action('init', function () { register_post_meta('property', 'project_id', [ 'show_in_rest' => true, 'single' => true, 'type' => 'integer', 'auth_callback' => '__return_true', ]); register_post_meta('property', 'project_name', [ 'show_in_rest' => true, 'single' => true, 'type' => 'integer', 'auth_callback' => '__return_true', ]); }); /* |-------------------------------------------------------------------------- | LINK PROJECT |-------------------------------------------------------------------------- */ add_action('rest_api_init', function () { register_rest_route('faam/v1', '/link-project', [ 'methods' => 'POST', 'permission_callback' => function () { return current_user_can('edit_posts'); }, 'callback' => function ($request) { $property_id = absint( $request->get_param('property_id') ); $project_id = absint( $request->get_param('project_id') ); if (!$property_id || !$project_id) { return new WP_Error( 'missing_data', 'property_id and project_id are required', ['status' => 400] ); } update_post_meta( $property_id, 'project_name', $project_id ); update_post_meta( $property_id, 'project_id', $project_id ); faam_sync_project_to_property($property_id); return [ 'success' => true, 'property_id' => $property_id, 'project_id' => $project_id, ]; } ]); }); /* |-------------------------------------------------------------------------- | CREATE PROPERTY |-------------------------------------------------------------------------- */ add_action('rest_api_init', function () { register_rest_route('faam/v1', '/create-property', [ 'methods' => 'POST', 'permission_callback' => function () { return current_user_can('edit_posts'); }, 'callback' => function ($request) { /* |-------------------------------------------------------------------------- | Basic Property |-------------------------------------------------------------------------- */ $title = sanitize_text_field( $request->get_param('title') ); if (empty($title)) { return new WP_Error( 'missing_title', 'title is required', ['status' => 400] ); } /* |-------------------------------------------------------------------------- | Create Property Post |-------------------------------------------------------------------------- */ $property_id = wp_insert_post([ 'post_type' => 'property', 'post_status' => 'publish', 'post_title' => $title, ]); if (is_wp_error($property_id)) { return $property_id; } /* |-------------------------------------------------------------------------- | Project ID |-------------------------------------------------------------------------- */ $project_id = absint( $request->get_param('project_id') ); if ($project_id) { update_post_meta( $property_id, 'project_id', $project_id ); update_post_meta( $property_id, 'project_name', $project_id ); if (function_exists('update_field')) { update_field( 'project_name', $project_id, $property_id ); } } /* |-------------------------------------------------------------------------- | Listing Information |-------------------------------------------------------------------------- */ update_post_meta( $property_id, 'fave_property_listing_code', $request->get_param('listing_code') ); update_post_meta( $property_id, 'fave_property_rent_price', $request->get_param('rent_price') ); update_post_meta( $property_id, 'fave_property_sale_price', $request->get_param('sale_price') ); update_post_meta( $property_id, 'fave_property_lease_start_date', $request->get_param('lease_start_date') ); update_post_meta( $property_id, 'fave_property_bedrooms', $request->get_param('bedrooms') ); update_post_meta( $property_id, 'fave_property_bathrooms', $request->get_param('bathrooms') ); update_post_meta( $property_id, 'fave_property_area_size', $request->get_param('land_size_sqm') ); update_post_meta( $property_id, 'fave_property_floor', $request->get_param('floor') ); update_post_meta( $property_id, 'fave_property_pet_friendly', $request->get_param('pet_friendly') ); update_post_meta( $property_id, 'fave_property_ev_charger', $request->get_param('ev_charger') ); update_post_meta( $property_id, 'fave_property_near_bts', $request->get_param('near_bts') ); update_post_meta( $property_id, 'fave_property_caption', $request->get_param('caption') ); /* |-------------------------------------------------------------------------- | Owner Information |-------------------------------------------------------------------------- */ update_post_meta( $property_id, 'co_owner', $request->get_param('co_owner') ); update_post_meta( $property_id, 'owner_name', $request->get_param('owner_name') ); update_post_meta( $property_id, 'phone', $request->get_param('phone') ); update_post_meta( $property_id, 'line_id', $request->get_param('line_id') ); update_post_meta( $property_id, 'whatsapp', $request->get_param('whatsapp') ); update_post_meta( $property_id, 'facebook', $request->get_param('facebook') ); update_post_meta( $property_id, 'caption', $request->get_param('caption') ); /* |-------------------------------------------------------------------------- | Houzez Meta |-------------------------------------------------------------------------- */ update_post_meta( $property_id, 'fave_property_price', $request->get_param('rent_price') ); update_post_meta( $property_id, 'fave_property_sec_price', $request->get_param('sale_price') ); update_post_meta( $property_id, 'fave_property_id', $request->get_param('listing_code') ); update_post_meta( $property_id, 'fave_property_year', $request->get_param('lease_start_date') ); update_post_meta( $property_id, 'fave_property_size', $request->get_param('land_size_sqm') ); update_post_meta( $property_id, 'fave_property_bedrooms', $request->get_param('bedrooms') ); update_post_meta( $property_id, 'fave_property_bathrooms', $request->get_param('bathrooms') ); update_post_meta( $property_id, 'fave_property_floor', $request->get_param('floor') ); update_post_meta( $property_id, 'fave_property_garage', $request->get_param('pet_friendly') ); update_post_meta( $property_id, 'fave_property_garage_size', $request->get_param('ev_charger') ); update_post_meta( $property_id, 'fave_property_rooms', $request->get_param('near_bts') ); update_post_meta( $property_id, 'fave_property_caption', $request->get_param('caption') ); /* |-------------------------------------------------------------------------- | Houzez Taxonomies |-------------------------------------------------------------------------- */ if ($request->get_param('property_type')) { wp_set_object_terms( $property_id, $request->get_param('property_type'), 'property_type' ); } if ($request->get_param('property_status')) { wp_set_object_terms( $property_id, $request->get_param('property_status'), 'property_status' ); } /* |-------------------------------------------------------------------------- | Sync Project → Property |-------------------------------------------------------------------------- */ faam_sync_project_to_property( $property_id ); /* |-------------------------------------------------------------------------- | Response |-------------------------------------------------------------------------- */ return [ 'success' => true, 'property_id' => $property_id, 'project_id' => $project_id, ]; } ]); }); /* |-------------------------------------------------------------------------- | AUTO SYNC PROJECT |-------------------------------------------------------------------------- */ add_action( 'acf/save_post', 'faam_sync_project_to_property', 20 ); add_action( 'save_post', 'faam_sync_project_to_property', 20 ); add_action( 'save_post_property', 'faam_sync_project_to_property', 20 ); /* |-------------------------------------------------------------------------- | SYNC PROJECT → PROPERTY |-------------------------------------------------------------------------- */ function faam_sync_project_to_property($post_id) { /* |-------------------------------------------------------------------------- | ตรวจสอบ Post Type |-------------------------------------------------------------------------- */ $post_type = get_post_type($post_id); if (!in_array( $post_type, ['property', 'properties'], true )) { return; } /* |-------------------------------------------------------------------------- | Prevent Loop |-------------------------------------------------------------------------- */ static $running = false; if ($running) { return; } $running = true; /* |-------------------------------------------------------------------------- | Debug Log |-------------------------------------------------------------------------- */ error_log( '==============================' ); error_log( 'FAAM CORE START' ); error_log( 'Property ID : ' . $post_id ); error_log( 'Post Type : ' . $post_type ); /* |-------------------------------------------------------------------------- | อ่าน Project ID จาก Meta ก่อน |-------------------------------------------------------------------------- */ $project_id = get_post_meta( $post_id, 'project_id', true ); error_log( 'Project ID Meta : ' . print_r( $project_id, true ) ); /* |-------------------------------------------------------------------------- | ถ้าไม่มี Project ID |-------------------------------------------------------------------------- */ if (empty($project_id)) { $project = get_field( 'project_name', $post_id ); error_log( 'Project Raw : ' . print_r( $project, true ) ); if (empty($project)) { $project = get_post_meta( $post_id, 'project_name', true ); error_log( 'Project Meta : ' . print_r( $project, true ) ); } if ($project instanceof WP_Post) { $project_id = $project->ID; } elseif (is_numeric($project)) { $project_id = intval($project); } } /* |-------------------------------------------------------------------------- | หา Project ไม่เจอ |-------------------------------------------------------------------------- */ if (empty($project_id)) { error_log( 'No Project Selected' ); $running = false; return; } /* |-------------------------------------------------------------------------- | ตรวจสอบ Project |-------------------------------------------------------------------------- */ $project_post = get_post( $project_id ); if (!$project_post) { error_log( 'Project Not Found : ' . $project_id ); $running = false; return; } error_log( 'Project ID : ' . $project_id ); /* |-------------------------------------------------------------------------- | รายชื่อ Field ที่จะ Copy |-------------------------------------------------------------------------- */ $fields = [ 'developer', 'property_type', 'completed_year', 'building_count', 'total_units', 'floor_count', 'parking', 'pet_friendly', 'ev_charger', 'highlight', 'address', 'subdistrict', 'district', 'province', 'area', 'latitude', 'longitude', 'google_place_id', 'station_name', 'postcode', 'description', 'project_id' ]; /* |-------------------------------------------------------------------------- | Copy ทุก Field จาก Project → Property |-------------------------------------------------------------------------- */ foreach ($fields as $field) { $value = get_field( $field, $project_id ); error_log( sprintf( '[COPY] %s => %s', $field, print_r( $value, true ) ) ); if ($value === null) { continue; } $updated = update_field( $field, $value, $post_id ); if ($updated === false) { update_post_meta( $post_id, $field, $value ); error_log( '[META] ' . $field . ' saved' ); } else { error_log( '[ACF] ' . $field . ' updated' ); } } /* |-------------------------------------------------------------------------- | บันทึก Project ID และ Project Name |-------------------------------------------------------------------------- */ update_post_meta( $post_id, 'project_id', $project_id ); update_post_meta( $post_id, 'project_name', $project_id ); if (function_exists('update_field')) { update_field( 'project_name', $project_id, $post_id ); } error_log( 'Project Link Saved' ); /* |-------------------------------------------------------------------------- | Sync Houzez |-------------------------------------------------------------------------- */ faam_sync_to_houzez( $post_id ); error_log( 'FAAM Sync Complete' ); error_log( '==============================' ); $running = false; } /* |-------------------------------------------------------------------------- | SYNC ACF → HOUZEZ META |-------------------------------------------------------------------------- */ function faam_sync_to_houzez($post_id) { /* |-------------------------------------------------------------------------- | FULL ADDRESS |-------------------------------------------------------------------------- */ $address = get_field( 'address', $post_id ); $subdistrict = get_field( 'subdistrict', $post_id ); $district = get_field( 'district', $post_id ); $province = get_field( 'province', $post_id ); $full_address = implode( ', ', array_filter([ $address, $subdistrict, $district, $province, 'Thailand', ]) ); /* |-------------------------------------------------------------------------- | SAVE HOUZEZ ADDRESS |-------------------------------------------------------------------------- */ if (!empty($full_address)) { update_post_meta( $post_id, 'fave_property_map_address', $full_address ); } /* |-------------------------------------------------------------------------- | GET LAT / LONG FROM PROJECT |-------------------------------------------------------------------------- */ $latitude = get_field( 'latitude', $post_id ); $longitude = get_field( 'longitude', $post_id ); /* |-------------------------------------------------------------------------- | ถ้า Project มี Lat / Long | ใช้ค่าของ Project โดยตรง |-------------------------------------------------------------------------- */ if ( is_numeric($latitude) && is_numeric($longitude) ) { $latitude = (float) $latitude; $longitude = (float) $longitude; } /* |-------------------------------------------------------------------------- | ถ้าไม่มีพิกัด | ให้ Geocode จาก Address อัตโนมัติ |-------------------------------------------------------------------------- */ if ( ( empty($latitude) || empty($longitude) || !is_numeric($latitude) || !is_numeric($longitude) ) && !empty($full_address) && function_exists('houzez_get_address_coordinates') ) { $coordinates = houzez_get_address_coordinates( $full_address ); if ( is_array($coordinates) && isset($coordinates['lat']) && isset($coordinates['lng']) && is_numeric($coordinates['lat']) && is_numeric($coordinates['lng']) ) { $latitude = (float) $coordinates['lat']; $longitude = (float) $coordinates['lng']; } } /* |-------------------------------------------------------------------------- | SAVE ACF LAT / LONG |-------------------------------------------------------------------------- */ if ( is_numeric($latitude) && is_numeric($longitude) ) { if (function_exists('update_field')) { update_field( 'latitude', $latitude, $post_id ); update_field( 'longitude', $longitude, $post_id ); } /* |-------------------------------------------------------------------------- | Houzez Geolocation |-------------------------------------------------------------------------- */ update_post_meta( $post_id, 'houzez_geolocation_lat', $latitude ); update_post_meta( $post_id, 'houzez_geolocation_long', $longitude ); /* |-------------------------------------------------------------------------- | สำคัญมาก | | Houzez Map ของเว็บเฟิร์นใช้ | fave_property_location = LAT,LONG | | ห้ามใส่ district ตรงนี้ |-------------------------------------------------------------------------- */ update_post_meta( $post_id, 'fave_property_location', $latitude . ',' . $longitude ); error_log( '[MAP] Latitude : ' . $latitude ); error_log( '[MAP] Longitude : ' . $longitude ); error_log( '[MAP] Location : ' . $latitude . ',' . $longitude ); } /* |-------------------------------------------------------------------------- | OTHER HOUZEZ META |-------------------------------------------------------------------------- */ $zip = get_field( 'postcode', $post_id ); if ($zip !== null && $zip !== '') { update_post_meta( $post_id, 'fave_property_zip', $zip ); } /* |-------------------------------------------------------------------------- | District | | เก็บ district แยก ไม่ใช้ fave_property_location |-------------------------------------------------------------------------- */ $district = get_field( 'district', $post_id ); if ($district !== null && $district !== '') { update_post_meta( $post_id, 'fave_property_area', $district ); } /* |-------------------------------------------------------------------------- | Province |-------------------------------------------------------------------------- */ $province = get_field( 'province', $post_id ); if ($province !== null && $province !== '') { update_post_meta( $post_id, 'fave_property_country', $province ); } /* |-------------------------------------------------------------------------- | CLEAR CACHE |-------------------------------------------------------------------------- */ clean_post_cache( $post_id ); if (function_exists('wp_cache_delete')) { wp_cache_delete( $post_id, 'posts' ); } error_log( 'Houzez Sync Finished' ); } add_action('rest_api_init', function () { register_rest_route('faam/v1', '/project-lookup', [ 'methods' => 'GET', 'permission_callback' => '__return_true', 'callback' => function (WP_REST_Request $request) { $search = sanitize_text_field( $request->get_param('search') ); if (empty($search)) { return new WP_Error( 'missing_search', 'Project search is required.', ['status' => 400] ); } $query = new WP_Query([ 'post_type' => 'projects', 'post_status' => 'publish', 'posts_per_page' => 10, 's' => $search, ]); $results = []; foreach ($query->posts as $project) { $results[] = [ 'id' => $project->ID, 'slug' => $project->post_name, 'title' => get_the_title($project->ID), ]; } return $results; }, ]); }); https://faamprop.com/wp-sitemap-posts-post-1.xmlhttps://faamprop.com/wp-sitemap-posts-page-1.xmlhttps://faamprop.com/wp-sitemap-posts-projects-1.xmlhttps://faamprop.com/wp-sitemap-posts-fts_builder-1.xmlhttps://faamprop.com/wp-sitemap-posts-property-1.xmlhttps://faamprop.com/wp-sitemap-posts-houzez_agency-1.xmlhttps://faamprop.com/wp-sitemap-posts-houzez_agent-1.xmlhttps://faamprop.com/wp-sitemap-taxonomies-category-1.xmlhttps://faamprop.com/wp-sitemap-taxonomies-post_tag-1.xmlhttps://faamprop.com/wp-sitemap-taxonomies-property_type-1.xmlhttps://faamprop.com/wp-sitemap-users-1.xml