Changeset 3418321
- Timestamp:
- 12/12/2025 01:47:34 PM (4 months ago)
- Location:
- houzez-property-feed/trunk
- Files:
-
- 9 edited
-
README.txt (modified) (2 diffs)
-
assets/js/admin-import.js (modified) (2 diffs)
-
houzez-property-feed.php (modified) (2 diffs)
-
includes/export-formats/class-houzez-property-feed-format-thinkspain.php (modified) (1 diff)
-
includes/format-functions.php (modified) (2 diffs)
-
includes/import-formats/class-houzez-property-feed-format-apimo.php (modified) (2 diffs)
-
includes/import-formats/class-houzez-property-feed-format-propctrl.php (modified) (11 diffs)
-
includes/import-formats/class-houzez-property-feed-format-vaultea.php (modified) (1 diff)
-
includes/views/admin-settings-import-settings-format.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
houzez-property-feed/trunk/README.txt
r3393603 r3418321 3 3 Tags: property import, property export, houzez, houzez import property, real estate 4 4 Requires at least: 3.8 5 Tested up to: 6. 86 Stable tag: 2.5.3 57 Version: 2.5.3 55 Tested up to: 6.9 6 Stable tag: 2.5.36 7 Version: 2.5.36 8 8 Homepage: https://houzezpropertyfeed.com 9 9 License: GPLv3 … … 145 145 == Changelog == 146 146 147 = 2.5.36 - 2025-12-12 = 148 * Added support for v6 of the propCtrl API used for agency integrations as opposed to importing from portals 149 * Added language option to Apimo imports 150 * Added support for commercial properties in VaultEA/VaultRE format 151 * Corrected XML node name of thinkSPAIN description node from 'desc' to 'description' 152 * Declared compatibility with WordPress 6.9 153 147 154 = 2.5.35 - 2025-11-11 = 148 155 * Added support for exporting in the thinkSPAIN XML format -
houzez-property-feed/trunk/assets/js/admin-import.js
r3389696 r3418321 417 417 418 418 jQuery('.hpf-admin-settings-import-settings .settings-panel #format').change(function() 419 { 420 hpf_show_format_settings(); 421 }); 422 423 jQuery('select[name=\'propctrl_api_version\']').change(function() 419 424 { 420 425 hpf_show_format_settings(); … … 1566 1571 jQuery('#import_setting_tab_media').show(); 1567 1572 jQuery('.hpf-admin-settings-import-settings .csv-rules-available-fields').show(); 1573 } 1574 1575 if ( selected_format == 'propctrl' ) 1576 { 1577 var selected_api_version = jQuery('select[name=\'propctrl_api_version\']').val(); 1578 if ( selected_api_version == 'v6' ) 1579 { 1580 jQuery('#row_propctrl_agency_id').hide(); 1581 jQuery('#row_propctrl_branch_id').hide(); 1582 } 1583 else 1584 { 1585 jQuery('#row_propctrl_agency_id').show(); 1586 jQuery('#row_propctrl_branch_id').show(); 1587 } 1568 1588 } 1569 1589 -
houzez-property-feed/trunk/houzez-property-feed.php
r3393603 r3418321 4 4 * Plugin Uri: https://houzezpropertyfeed.com 5 5 * Description: Automatically import properties to Houzez from estate agency CRMs and export to portals 6 * Version: 2.5.3 56 * Version: 2.5.36 7 7 * Author: PropertyHive 8 8 * Author URI: https://wp-property-hive.com … … 20 20 * @var string 21 21 */ 22 public $version = '2.5.3 5';22 public $version = '2.5.36'; 23 23 24 24 /** -
houzez-property-feed/trunk/includes/export-formats/class-houzez-property-feed-format-thinkspain.php
r3393603 r3418321 246 246 $description = preg_replace('/<!--\s*\/wp:.*?-->/s', '', $description); 247 247 248 $desc_xml = $property_xml->addChild('desc ');248 $desc_xml = $property_xml->addChild('description'); 249 249 $desc_xml->addChild('en', htmlspecialchars($description, ENT_QUOTES | ENT_XML1, 'UTF-8')); 250 250 -
houzez-property-feed/trunk/includes/format-functions.php
r3393603 r3418321 391 391 'label' => __( 'Agency ID', 'houzezpropertyfeed' ), 392 392 'type' => 'text', 393 ) 393 ), 394 array( 395 'id' => 'language', 396 'label' => __( 'Language', 'houzezpropertyfeed' ), 397 'type' => 'text', 398 'default' => 'en', 399 'tooltip' => __( 'A two letter country code (e.g. en, es, fr)', 'houzezpropertyfeed' ) 400 ), 394 401 ), 395 402 'address_fields' => array( 'district', 'city', 'region' ), … … 1979 1986 'name' => __( 'PropCtrl', 'houzezpropertyfeed' ), 1980 1987 'fields' => array( 1988 array( 1989 'id' => 'api_version', 1990 'label' => __( 'API Version', 'houzezpropertyfeed' ), 1991 'type' => 'select', 1992 'options' => array( 1993 '' => 'Listing Service v1 (if you\'re a portal importing from multiple agents)', 1994 'v6' => 'Agency Integration Service v6 (if you\'re a single agency)', 1995 ) 1996 ), 1981 1997 array( 1982 1998 'id' => 'base_url', -
houzez-property-feed/trunk/includes/import-formats/class-houzez-property-feed-format-apimo.php
r3389596 r3418321 158 158 $start_at_property = get_option( 'houzez_property_feed_property_' . $this->import_id ); 159 159 160 $language = 'en'; 161 if ( isset($import_settings['language']) && !empty($import_settings['language']) ) 162 { 163 $language = strtolower(trim($import_settings['language'])); 164 } 165 160 166 $property_row = 1; 161 167 foreach ( $this->properties as $property ) … … 205 211 foreach ( $property['comments'] as $comment ) 206 212 { 207 if ( isset($comment['language']) && $comment['language'] == 'en')213 if ( isset($comment['language']) && strtolower(trim($comment['language'])) == $language ) 208 214 { 209 215 if ( isset($comment['title']) && !empty($comment['title']) ) { $display_address = $comment['title']; } 210 216 if ( isset($comment['comment']) && !empty($comment['comment']) ) { $post_content = $comment['comment']; } 211 217 break; 218 } 219 } 220 } 221 222 if ( $language != 'en' && empty($display_address) && empty($post_content) ) 223 { 224 // No title/desc found in language specified. Fallback to en 225 if ( isset($property['comments']) && !empty($property['comments']) ) 226 { 227 foreach ( $property['comments'] as $comment ) 228 { 229 if ( isset($comment['language']) && strtolower(trim($comment['language'])) == 'en' ) 230 { 231 if ( isset($comment['title']) && !empty($comment['title']) ) { $display_address = $comment['title']; } 232 if ( isset($comment['comment']) && !empty($comment['comment']) ) { $post_content = $comment['comment']; } 233 break; 234 } 212 235 } 213 236 } -
houzez-property-feed/trunk/includes/import-formats/class-houzez-property-feed-format-propctrl.php
r3389596 r3418321 55 55 56 56 // Send request back to PropCtrl containing post ID and URL etc 57 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/listings/' . $crm_id; 57 if ( isset($import_settings['api_version']) && $import_settings['api_version'] == 'v6' ) 58 { 59 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/properties/' . $crm_id; 60 } 61 else 62 { 63 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/listings/' . $crm_id; 64 } 58 65 59 66 $headers = array( … … 95 102 public function parse() 96 103 { 104 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 105 106 if ( isset($import_settings['api_version']) && $import_settings['api_version'] == 'v6' ) 107 { 108 $parsed = $this->parse_v6(); 109 110 if ( !$parsed ) 111 { 112 return false; 113 } 114 } 115 else 116 { 117 $parsed = $this->parse_v1(); 118 if ( !$parsed ) 119 { 120 return false; 121 } 122 } 123 124 return true; 125 } 126 127 public function parse_v1() 128 { 129 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 130 97 131 $this->properties = array(); // Reset properties in the event we're importing multiple files 98 132 … … 100 134 101 135 $this->time_at_start = time(); 102 103 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id );104 136 105 137 $from_date = '2020-01-01 00:00:00'; … … 387 419 return false; 388 420 } 421 422 return true; 389 423 } 390 424 391 p rivate function get_agency_details( $agency_id)425 public function parse_v6() 392 426 { 393 if ( isset($this->agency_cache[$agency_id]) )394 {395 return $this->agency_cache[$agency_id];396 }397 398 427 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 399 428 400 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/agencies?agencyIds=' . $agency_id; 429 $this->properties = array(); // Reset properties in the event we're importing multiple files 430 431 $this->log("Parsing properties", '', 0, '', false); 432 433 $this->time_at_start = time(); 434 435 $from_date = '2020-01-01 00:00:00'; 436 if ( ( isset($import_settings['only_updated']) && $import_settings['only_updated'] == 'yes' ) || !isset($import_settings['only_updated']) ) 437 { 438 // get last ran date 439 $last_ran_date = get_option( 'houzez_property_feed_last_ran_' . $this->import_id, '' ); 440 if ( !empty($last_ran_date) ) 441 { 442 $date = new DateTime(); 443 $date->setTimestamp($last_ran_date); 444 $date->setTimezone(new DateTimeZone('Africa/Johannesburg')); 445 $from_date = $date->format('Y-m-d H:i:s'); 446 447 $this->only_updated = true; 448 } 449 } 450 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/properties/changes?fromDate=' . $from_date; 451 452 $this->log("Making request to " . $url); 401 453 402 454 $headers = array( … … 415 467 if ( is_wp_error( $response ) ) 416 468 { 417 $this->log_error( ' AgencyResponse: ' . $response->get_error_message() );469 $this->log_error( 'Response: ' . $response->get_error_message() ); 418 470 419 471 return false; 420 472 } 421 473 474 if ( wp_remote_retrieve_response_code($response) === 401 ) 475 { 476 $this->log_error( wp_remote_retrieve_response_code($response) . ' response received when requesting properties. Error message: ' . wp_remote_retrieve_response_message($response) ); 477 return false; 478 } 479 422 480 $json = json_decode( $response['body'], TRUE ); 423 481 424 482 if ($json !== FALSE) 425 483 { 426 if ( is_array($json) && !empty($json) ) 427 { 428 $this->agency_cache[$agency_id] = $json[0]; 429 return $json[0]; 484 if ( isset($json['items']) ) 485 { 486 if ( !empty($json['items']) ) 487 { 488 $this->log("Found " . number_format(count($json['items'])) . " properties to import. Getting further details by getting properties in " . number_format(ceil( count($json['items']) / 10 )) . " batches of 10"); 489 490 $property_ids_in_batch = array(); 491 492 foreach ( $json['items'] as $property ) 493 { 494 if ( count($property_ids_in_batch) == 10 ) 495 { 496 $done = $this->get_properties_in_batch_v6( $property_ids_in_batch ); 497 498 if ( $done === false ) 499 { 500 return false; 501 } 502 503 $property_ids_in_batch = array(); 504 } 505 506 $property_ids_in_batch[] = $property['id']; 507 } 508 509 $done = $this->get_properties_in_batch_v6( $property_ids_in_batch ); 510 511 if ( $done === false ) 512 { 513 return false; 514 } 515 } 430 516 } 431 517 else 432 518 { 433 $this->log_error( 'Parsed agency but it\'s empty: ' . $response['body'] );519 $this->log_error( 'Parsed JSON but no properties found: ' . $response['body'] ); 434 520 435 521 return false; … … 439 525 { 440 526 // Failed to parse JSON 441 $this->log_error( 'Failed to parse agencyJSON: ' . $response['body'] );527 $this->log_error( 'Failed to parse JSON: ' . $response['body'] ); 442 528 443 529 return false; 444 530 } 445 531 446 return false; 532 if ( empty($this->properties) ) 533 { 534 if ( $this->only_updated === true ) 535 { 536 update_option( 'houzez_property_feed_last_ran_' . $this->import_id, $this->time_at_start ); 537 $this->log_error( 'No properties modified since the last time an import ran.' ); 538 } 539 else 540 { 541 $this->log_error( 'No properties found. We\'re not going to continue as this could likely be wrong and all properties will get removed if we continue.' ); 542 } 543 return false; 544 } 545 546 return true; 447 547 } 448 548 449 private function get_ branch_details( $branch_id)549 private function get_properties_in_batch_v6( $property_ids = array() ) 450 550 { 451 if ( isset($this->branch_cache[$branch_id]) )452 { 453 return $this->branch_cache[$branch_id];551 if ( empty($property_ids) ) 552 { 553 return false; 454 554 } 455 555 456 556 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 457 557 458 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/branches?branchIds=' . $branch_id; 558 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/properties?'; 559 560 // Use array_map to prepend "listingIds=" to each ID 561 $listing_ids = array_map(function($id) { 562 return "propertyIds=" . $id; 563 }, $property_ids); 564 565 // Use implode to concatenate them with "&" 566 $url .= implode("&", $listing_ids); 459 567 460 568 $headers = array( 461 569 'Authorization' => 'Basic ' . base64_encode($import_settings['api_username'] . ':' . $import_settings['api_password']), 462 570 ); 571 572 $this->log("Making request to " . $url); 463 573 464 574 $response = wp_remote_request( … … 473 583 if ( is_wp_error( $response ) ) 474 584 { 475 $this->log_error( ' BranchResponse: ' . $response->get_error_message() );585 $this->log_error( 'Response: ' . $response->get_error_message() ); 476 586 477 587 return false; … … 480 590 $json = json_decode( $response['body'], TRUE ); 481 591 592 $off_market_listing_statuses = apply_filters( 'houzez_property_feed_propctrl_off_market_statuses', array('cancelled', 'withdrawn', 'expired', 'rented', 'sold') ); 593 482 594 if ($json !== FALSE) 483 595 { 484 if ( is_array($json) && !empty($json) ) 485 { 486 $this->branch_cache[$branch_id] = $json[0]; 487 return $json[0]; 596 if ( is_array($json) ) 597 { 598 if ( !empty($json) ) 599 { 600 foreach ( $json as $property ) 601 { 602 if ( 603 isset($property['listingStatus']) && 604 in_array(strtolower($property['listingStatus']), $off_market_listing_statuses) 605 ) 606 { 607 $this->remove_property( $property['propertyId'], '' ); 608 continue; 609 } 610 611 $property['listingId'] = $property['propertyId']; 612 613 list($suburb, $city, $province, $postcode, $country) = $this->get_suburb_info($property['suburbId']); 614 615 $property['suburb'] = $suburb; 616 $property['city'] = $city; 617 $property['province'] = $province; 618 $property['postcode'] = $postcode; 619 $property['country'] = $country; 620 621 $property['agencyDetails'] = array(); 622 $property['branchDetails'] = array(); 623 $property['agentDetails'] = array(); 624 625 if ( isset($property['agencyId']) && !empty($property['agencyId']) ) 626 { 627 $agency = $this->get_agency_details($property['agencyId']); 628 629 if ( $agency !== FALSE ) 630 { 631 $property['agencyDetails'] = $agency; 632 } 633 } 634 635 if ( isset($property['branchId']) && !empty($property['branchId']) ) 636 { 637 $branch = $this->get_branch_details($property['branchId']); 638 639 if ( $branch !== FALSE ) 640 { 641 $property['branchDetails'] = $branch; 642 } 643 } 644 645 if ( isset($property['agents']) && !empty($property['agents']) && is_array($property['agents']) ) 646 { 647 foreach ( $property['agents'] as $agent_id ) 648 { 649 $agent = $this->get_agent_details($agent_id); 650 651 if ( $agent !== FALSE ) 652 { 653 $property['agentDetails'][] = $agent; 654 } 655 } 656 } 657 658 $this->properties[] = $property; 659 660 } 661 } 662 else 663 { 664 $this->log_error( 'Parsed property JSON but it\'s empty: ' . $response['body'] ); 665 666 //return false; 667 } 488 668 } 489 669 else 490 670 { 491 $this->log_error( 'Parsed branch JSON but it\'s empty: ' . $response['body'] );671 $this->log_error( 'Parsed property JSON but it\'s not an array: ' . $response['body'] ); 492 672 493 673 return false; … … 497 677 { 498 678 // Failed to parse JSON 499 $this->log_error( 'Failed to parse branchJSON: ' . $response['body'] );679 $this->log_error( 'Failed to parse property JSON: ' . $response['body'] ); 500 680 501 681 return false; 502 682 } 503 683 504 return false;684 return true; 505 685 } 506 686 507 private function get_agen t_details( $agent_id )687 private function get_agency_details( $agency_id ) 508 688 { 509 if ( isset($this->agen t_cache[$agent_id]) )510 { 511 return $this->agen t_cache[$agent_id];689 if ( isset($this->agency_cache[$agency_id]) ) 690 { 691 return $this->agency_cache[$agency_id]; 512 692 } 513 693 514 694 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 515 695 516 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/agents?agentIds=' . $agent_id; 696 if ( isset($import_settings['api_version']) && $import_settings['api_version'] == 'v6' ) 697 { 698 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/agencies?agencyIds=' . $agency_id; 699 } 700 else 701 { 702 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/agencies?agencyIds=' . $agency_id; 703 } 517 704 518 705 $headers = array( … … 531 718 if ( is_wp_error( $response ) ) 532 719 { 720 $this->log_error( 'Agency Response: ' . $response->get_error_message() ); 721 722 return false; 723 } 724 725 $json = json_decode( $response['body'], TRUE ); 726 727 if ($json !== FALSE) 728 { 729 if ( is_array($json) && !empty($json) ) 730 { 731 $this->agency_cache[$agency_id] = $json[0]; 732 return $json[0]; 733 } 734 else 735 { 736 $this->log_error( 'Parsed agency but it\'s empty: ' . $response['body'] ); 737 738 return false; 739 } 740 } 741 else 742 { 743 // Failed to parse JSON 744 $this->log_error( 'Failed to parse agency JSON: ' . $response['body'] ); 745 746 return false; 747 } 748 749 return false; 750 } 751 752 private function get_branch_details( $branch_id ) 753 { 754 if ( isset($this->branch_cache[$branch_id]) ) 755 { 756 return $this->branch_cache[$branch_id]; 757 } 758 759 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 760 761 if ( isset($import_settings['api_version']) && $import_settings['api_version'] == 'v6' ) 762 { 763 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/branches?branchIds=' . $branch_id; 764 } 765 else 766 { 767 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/branches?branchIds=' . $branch_id; 768 } 769 770 $headers = array( 771 'Authorization' => 'Basic ' . base64_encode($import_settings['api_username'] . ':' . $import_settings['api_password']), 772 ); 773 774 $response = wp_remote_request( 775 $url, 776 array( 777 'method' => 'GET', 778 'timeout' => 120, 779 'headers' => $headers 780 ) 781 ); 782 783 if ( is_wp_error( $response ) ) 784 { 785 $this->log_error( 'Branch Response: ' . $response->get_error_message() ); 786 787 return false; 788 } 789 790 $json = json_decode( $response['body'], TRUE ); 791 792 if ($json !== FALSE) 793 { 794 if ( is_array($json) && !empty($json) ) 795 { 796 $this->branch_cache[$branch_id] = $json[0]; 797 return $json[0]; 798 } 799 else 800 { 801 $this->log_error( 'Parsed branch JSON but it\'s empty: ' . $response['body'] ); 802 803 return false; 804 } 805 } 806 else 807 { 808 // Failed to parse JSON 809 $this->log_error( 'Failed to parse branch JSON: ' . $response['body'] ); 810 811 return false; 812 } 813 814 return false; 815 } 816 817 private function get_agent_details( $agent_id ) 818 { 819 if ( isset($this->agent_cache[$agent_id]) ) 820 { 821 return $this->agent_cache[$agent_id]; 822 } 823 824 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 825 826 if ( isset($import_settings['api_version']) && $import_settings['api_version'] == 'v6' ) 827 { 828 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/agents?agentIds=' . $agent_id; 829 } 830 else 831 { 832 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/agents?agentIds=' . $agent_id; 833 } 834 835 836 $headers = array( 837 'Authorization' => 'Basic ' . base64_encode($import_settings['api_username'] . ':' . $import_settings['api_password']), 838 ); 839 840 $response = wp_remote_request( 841 $url, 842 array( 843 'method' => 'GET', 844 'timeout' => 120, 845 'headers' => $headers 846 ) 847 ); 848 849 if ( is_wp_error( $response ) ) 850 { 533 851 $this->log_error( 'Agent Response: ' . $response->get_error_message() ); 534 852 … … 574 892 $import_settings = houzez_property_feed_get_import_settings_from_id( $this->import_id ); 575 893 576 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/suburbs?suburbIds=' . $suburb_id; 894 if ( isset($import_settings['api_version']) && $import_settings['api_version'] == 'v6' ) 895 { 896 $url = rtrim($import_settings['base_url'], '/') . '/agency-integration/v6/suburbs?suburbIds=' . $suburb_id; 897 } 898 else 899 { 900 $url = rtrim($import_settings['base_url'], '/') . '/listing/v1/suburbs?suburbIds=' . $suburb_id; 901 } 577 902 578 903 $headers = array( -
houzez-property-feed/trunk/includes/import-formats/class-houzez-property-feed-format-vaultea.php
r3393603 r3418321 80 80 'department' => 'residential-lettings' 81 81 ), 82 /*array(82 array( 83 83 'uri' => 'properties/commercial/sale', 84 'department' => ' commercial',84 'department' => 'residential-sales', 85 85 'portalStatus' => array( 'listing', 'conditional' ) 86 86 ), 87 87 array( 88 88 'uri' => 'properties/commercial/lease', 89 'department' => ' commercial'90 ), */89 'department' => 'residential-lettings' 90 ), 91 91 array( 92 92 'uri' => 'properties/land/sale', -
houzez-property-feed/trunk/includes/views/admin-settings-import-settings-format.php
r3389696 r3418321 51 51 } 52 52 ?> 53 <tr >53 <tr id="row_<?php echo esc_attr($key . '_' . $field['id']); ?>"> 54 54 <th><?php echo isset($field['label']) ? esc_html($field['label']) : ''; ?></th> 55 55 <td><?php
Note: See TracChangeset
for help on using the changeset viewer.