· 6 years ago · Jul 23, 2019, 01:28 PM
1<?php
2/*
3 Plugin Name: Property Stream - Property Import from Perry
4 Plugin URI: http://www.propertystream.co/
5 Description: Import your properties from the Perry Feed
6 Version: 2.0.12
7 Author: PropertyStream
8 Author URI: http://www.propertystream.co/
9 Copyright: 2018 Property Stream
10 Text Domain: propertystreamperry
11 Domain Path: /lang
12 */
13
14/**
15 * Plugin security
16 */
17if ( !defined('ABSPATH') ) {
18 die();
19}
20
21$perry_dir = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'blm' . DIRECTORY_SEPARATOR;
22$perry_url = WP_CONTENT_URL . '/uploads/blm/';
23
24/** Plugin set definitions */
25define('PSIMPORT_PERRY_PLUGIN_SLUG', 'ps-perry-import');
26define('PSIMPORT_PERRY_PLUGIN_FILE', __FILE__);
27define('PSIMPORT_PERRY_PLUGIN_PATH', plugin_dir_path(__FILE__));
28define('PSIMPORT_PERRY_PLUGIN_URL', plugin_dir_url(__FILE__));
29define('PERRY_FILES_LOCATION', '');
30define('PERRY_IMAGE_URL', $perry_url . 'img/');
31define('PERRY_IMAGE_DIR', $perry_dir . 'img/');
32define('PERRY_FTP_DIR', $perry_dir . 'ftp/');
33define('PERRY_ARCHIVE_DIR', $perry_dir . 'archive/');
34define('PERRY_TMP_DIR', $perry_dir . 'tmp/');
35define('PSIMPORT_PERRY_PLUGIN_UUID', '5b2cd082b776fc7a8f603544');
36
37/** Kernl */
38require 'plugin_update_check.php';
39$MyUpdateChecker = new PluginUpdateChecker_2_0 (
40 'https://kernl.us/api/v1/updates/' . PSIMPORT_PERRY_PLUGIN_UUID,
41 __FILE__,
42 PSIMPORT_PERRY_PLUGIN_SLUG,
43 1
44);
45
46/** Plugin include required files */
47require_once( ABSPATH . 'wp-admin/includes/image.php' );
48
49/** Action hooks */
50add_action('init', ['Ps_Perry_Import_To_Post', 'init'], 9);
51add_action('wp', ['Ps_Perry_Import_To_Post', 'wp'], 9);
52add_action( 'parse_request', ['Ps_Perry_Import_To_Post', 'get_prod_by_ref'], 0 );
53add_filter('post_type_link', ['Ps_Perry_Import_To_Post', 'permalink_structure'], 10, 3);
54
55
56class Ps_Perry_Import_To_Post
57{
58
59 /**
60 * Add values to generate shortcodes
61 * @access private
62 * @var array
63 */
64 private static $shortcode_tags = [];
65
66 /**
67 * Holds the values to be used in the fields callbacks
68 * @access private
69 * @var array
70 */
71 private static $options = [];
72
73 /**
74 * Switch to allow us to do a full import oF all properties
75 * @access private
76 * @var boolean
77 */
78 private static $full_import = true;
79
80 /**
81 * Prefix for our XML import filename
82 * @access private
83 * @var string
84 */
85 private static $xml = 'https://perry-images.ams3.digitaloceanspaces.com/Images/Perry_RealtyXMLFeed.xml';
86
87 /**
88 * Is this running via CLI
89 * @access private
90 * @var boolean
91 */
92 private static $cli = false;
93
94 /**
95 * Called on WordPress init hook to set options and run importer if actioned
96 * @uses self::import()
97 * @uses get_option()
98 * @access public
99 * @static
100 * @final
101 * @return null
102 */
103 final public static function init()
104 {
105 self::register_taxonomies();
106 //self::url_rewrite();
107 return null;
108 }
109
110 /**
111 * Set up the URL rewrites for our plugin so that
112 * role ID will redirect to the property
113 * @method url_rewrite
114 * @final
115 * @access public
116 * @static
117 * @return null
118 */
119
120
121 final public static function get_prod_by_ref( $wp )
122 {
123
124 // Check if the request/page path begins with /malta-property/<trans_type>/<location>/<reference>
125 if ( preg_match( '#^malta-property/([^/]*)/([^/]*)/([^/]+)#', $wp->request, $matches ) ) {
126 //die(var_dump($matches));
127 $posts = get_posts( [
128 'post_type' => 'property',
129 'meta_key' => 'propertystream_agent_ref',
130 'meta_value' => $matches[3],
131 'posts_per_page' => 1,
132 ] );
133
134 if ( ! empty( $posts ) ) {
135
136 $wp->query_vars['name'] = $posts[0]->post_name;
137 $wp->query_vars['post_type'] = 'property'; // must set post type
138 }
139 }
140}
141
142 /**
143 *
144 *
145 */
146 final public static function permalink_structure ($permalink, $post, $leavename)
147 {
148 if (false !== strpos($permalink, '%reference%') && false !== strpos($permalink, '%location%') && false !== strpos($permalink, '%trans_type%')) {
149 $reference = get_post_meta($post->ID, 'propertystream_agent_ref', true);
150 $location = wp_get_post_terms($post->ID, 'location');
151 $type = wp_get_post_terms($post->ID, 'trans_type_id');
152 //check trans_type_id is set, it it is and is resale the slug should be sales. otherwise just assign it the value
153 if (!empty($type)) {
154 if ($type[0]->slug == 'resale') {
155 $type = 'sales';
156 }
157 else
158 {
159 $type = $type[0]->slug;
160 }
161 }
162 else {
163 $type = null;
164 }
165
166 $location = !empty($location) ? $location[0]->name : null;
167 $rewritecode = array(
168 '%reference%',
169 '%location%',
170 '%trans_type%'
171 );
172 $rewritereplace = array(
173 $reference,
174 $location,
175 $type,
176 );
177 $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
178 }
179 return $permalink;
180 }
181
182
183 /**
184 * Redirect on the WP hook if rezi role id is set
185 * @method wp
186 * @final
187 * @access public
188 * @static
189 * @return null
190 */
191 final public static function wp()
192 {
193 global $wpdb;
194 if(!empty($_GET['r'])) {
195 return null;
196 }
197 if(!empty($_GET['pid']) && empty($_GET['r'])) {
198 $sql = "SELECT {$wpdb->posts}.`post_name` FROM {$wpdb->postmeta}
199 INNER JOIN {$wpdb->posts} ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID
200 WHERE `meta_key`='propertystream_agent_ref'
201 AND `meta_value` = '".$_GET['pid']."'";
202 $result = $wpdb->get_results($sql);
203 $post_name = $result[0]->post_name;
204 wp_redirect('/malta-property/'.$_GET['pid'].'/'.$post_name.'?r=1');
205 exit();
206 }
207 if(strpos($_SERVER['REQUEST_URI'], '/malta-property/') !== false && empty($_GET['r'])) {
208 $arr1 = explode('/', $_SERVER['REQUEST_URI']);
209 $arr2 = explode('-', $arr1[3]);
210 if (preg_match('/[A-Za-z]/', $arr2[count($arr2)-1]) && preg_match('/[0-9]/', $arr2[count($arr2)-1])) {
211 // do nothing
212 return null;
213 } else {
214 wp_redirect('/?pid='.$arr1[2]);
215 exit();
216 }
217 }
218 return null;
219 }
220
221
222 /**
223 * Register our plugin taxonomies
224 * @access private
225 * @static
226 * @final
227 */
228 final public static function register_taxonomies ()
229 {
230 $taxonomies = [
231 [
232 'name' => 'location',
233 'label' => 'Location'
234 ]
235 ];
236
237 foreach ($taxonomies as $taxonomy) {
238 if (!taxonomy_exists($taxonomy['name'])) {
239 register_taxonomy(
240 $taxonomy['name'],
241 'property',
242 ['label' => __( $taxonomy['label'] ), 'public' => true, 'rewrite' => true, 'hierarchical' => true]
243 );
244 }
245 }
246 }
247
248 /**
249
250 */
251 final public static function import ()
252 {
253 global $wpdb;
254 self::$options = get_option(PSIMPORT_PERRY_PLUGIN_SLUG . '-options');
255 error_log('Property import starting:');
256
257 $active_properties = [];
258 $delete_properties = [];
259
260 $xml = self::get_xml($full);
261
262 $branch_id = 'PerryEstates';
263
264 foreach($xml as $property) {
265
266 // Get property information from feed
267 $property_id = $property->internal_id->__toString();
268
269 // Create or use WordPress user
270 // echo "\nSetting owner of property in CMS...'";
271 $user_id = self::set_user($property->agent);
272
273 // Create custom post data and save to database
274 // echo "\nSetting the custom post data...'";
275 $data = self::set_post_data($property, $property_id);
276 $new_property = self::set_post($data, $user_id, $property_id);
277
278 // Store property in active list so we can delete inactive properties later
279 // echo "\nStoring the active property...'";
280 array_push($active_properties, $new_property);
281
282 // Set the taxonomies
283 // echo "\nSetting the taxonomies for the property...'";
284 self::set_taxonomies($property, $new_property);
285
286 // Set the attachments
287 // echo "\nSetting the attachments (images etc)...'";
288 self::set_attachments($new_property, $property);
289
290 // Set the postmeta
291 // echo "\nSetting the additional data (postmeta)...'";
292 $postmeta = self::get_postmeta($property, $branch_id, $property_id);
293 self::set_post_meta($postmeta, $new_property);
294
295 // Completed property log
296 echo "\nProperty $property_id imported.";
297
298 }
299 echo "\nThe import is complete.... cleaning up old files and properties...";
300 self::move_properties_to_trash($active_properties);
301 echo "\nAll done. ".count($active_properties)." properties were imported. Have a nice day.";
302 }
303
304 /**
305 * Get the XML file and convert to usable format for import
306 * @access public
307 * @static
308 * @final
309 * @return SimpleXMLElement $xml
310 */
311 final public static function get_xml ()
312 {
313 echo "\nThe import file: " . self::$xml . " is now downloading.";
314 $get = file_get_contents(self::$xml);
315 $xml = simplexml_load_string($get);
316 echo "\nThe import file: " . self::$xml . " is now prepared for import.";
317 return $xml;
318 }
319
320 /**
321 * Create or use the branch_id as the WordPress user so that
322 * this is the author of the custom post
323 * @var int $branch_id
324 * @param SimpleXMLElement $agent
325 * @uses username_exists()
326 * @uses email_exists()
327 * @uses wp_generate_password()
328 * @uses wp_create_user()
329 * @uses sanitize_title()
330 * @access public
331 * @static
332 * @final
333 * @return int $user_id
334 */
335 final public static function set_user (SimpleXMLElement $agent)
336 {
337 if(!empty($agent->email)) {
338 $email = $agent->email->__toString();
339 } else {
340 $email = 'noreply@perry.com.mt';
341 }
342
343 $user_id = username_exists($email);
344 if (!$user_id && email_exists($email) == false) {
345 $random_password = wp_generate_password(12, false);
346
347 $userdata = [
348 'user_username' => $email,
349 'user_login' => $email,
350 'user_pass' => $random_password,
351 'user_nicename' => !empty($agent->branch_name) ? sanitize_title($agent->branch_name->__toString()) : null,
352 'display_name' => !empty($agent->branch_name) ? $agent->branch_name->__toString() : null,
353 'user_email' => $email
354 ];
355
356 $user_id = wp_insert_user($userdata);
357
358 // add user meta
359 $meta = [
360 'phone' => !empty($agent->phone) ? $agent->phone->__toString() : null,
361 'first_name' => !empty($agent->name) ? $agent->name->__toString() : null,
362 'designation' => !empty($agent->designation) ? $agent->designation->__toString() : null,
363 'description' => !empty($agent->intro_text) ? $agent->intro_text->__toString() : null,
364 'locale' => !empty($agent->locale) ? $agent->locale->__toString() : null,
365 'image_url' => !empty($agent->image_url) ? $agent->image_url->__toString() : null
366 ];
367 foreach($meta as $key => $value) {
368 update_user_meta($user_id, $key, $value);
369 }
370 }
371 return $user_id;
372 }
373
374
375 /**
376 * Create the custom post data for our property custom post type
377 * @var SimpleXMLElement $property The property object
378 * @var int $property_id The property id
379 * @uses sanitize_title()
380 * @access public
381 * @static
382 * @final
383 * @return int $user_id
384 */
385 final public static function set_post_data (SimpleXMLElement $property, $property_id)
386 {
387 $data = ['AGENT_REF' => $property->display_name->__toString() . ' ('.$property_id.') (PERRY)',
388 'DESCRIPTION' => !empty($property->description) ? $property->description->__toString() : null,
389 'SUMMARY' => !empty($property->property_type) ? $property->property_type->__toString() . ' ('.$property->property_subtype->__toString().')' : null,
390 'DISPLAY_ADDRESS' => $property->display_name->__toString(),
391 ];
392 return $data;
393 }
394
395
396 /**
397 * Set the taxonomies for our custom post based on the information from the feed
398 * @var SimpleXMLElement $property The property object
399 * @var integer $new_property The ID from WordPress post table for new property record
400 * @uses self::set_t_frequency()
401 * @uses self::set_trans_type_id()
402 * @uses self::set_status()
403 * @uses wp_set_object_terms()
404 * @global $wpdb WordPress database object
405 * @access public
406 * @static
407 * @final
408 * @return null
409 */
410 final public static function set_taxonomies (SimpleXMLElement $property, $new_property)
411 {
412 global $wpdb;
413
414 $taxonomies = [];
415
416 $taxonomies['location'] = $property->location->__toString();
417
418 $taxonomies['trans_type_id'] = self::set_trans_type_id($property);
419
420 if(isset($property->let_frequency)) {
421 $taxonomies['let_rent_frequency'] = $property->let_frequency->__toString();
422 }
423
424 $taxonomies['prop_sub_id'] = [
425 $property->property_type->__toString(),
426 $property->property_subtype->__toString(),
427 ];
428
429 if($property->property_attributes->__toString() === 'Furnished') {
430 $taxonomies['let_furn_id'] = 'Furnished';
431 } else {
432 $taxonomies['let_furn_id'] = 'Unfurnished';
433 }
434 // $taxonomies['tenure_type_id'] = $property->tenure->__toString();
435 // $taxonomies['status_id'] = $property->status->__toString();
436
437 foreach($taxonomies as $taxonomy => $term) {
438 $var = wp_set_object_terms($new_property, $term, $taxonomy);
439 }
440
441 return null;
442 }
443
444
445 /**
446 * Set the Trans Type ID (Resale or Lettings) to be the equivalent BLM value
447 * @var SimpleXMLElement $property The property object
448 * @access public
449 * @static
450 * @final
451 * @return
452 */
453 final public static function set_trans_type_id (SimpleXMLElement $property)
454 {
455 if($property->tenure->__toString() === "Sale") {
456 return 'Resale';
457 } else {
458 return 'Lettings';
459 }
460 }
461
462 /**
463 * Generate an array that we can use to save postmeta for our property custom post type object
464 * @var SimpleXMLElement $property The property object
465 * @var int $branch_id
466 * @var int $property_id
467 * @uses self::set_features()
468 * @access public
469 * @static
470 * @final
471 * @return array The array of postmeta to save
472 */
473 final public static function get_postmeta (SimpleXMLElement $property, $branch_id, $property_id)
474 {
475
476 $postmeta = [
477 'propertystream_bedrooms' => !empty($property->bedrooms) ? $property->bedrooms->__toString() : 0,
478 'propertystream_bathrooms' => !empty($property->bathrooms) ? $property->bathrooms->__toString() : 0,
479 'propertystream_branch_id' => !empty($property->agent->branch_name) ? $property->agent->branch_name->__toString() : null,
480 'propertystream_agent' => !empty($property->agent->email) ? $property->agent->email->__toString() : null,
481 'propertystream_commercial' => !empty($property->commercial) ? $property->commercial->__toString() : null,
482 'propertystream_features' => self::set_features($property),
483 'propertystream_attributes' => !empty($property->property_attributes) ? $property->property_attributes->__toString() : null,
484 'propertystream_agent_ref' => !empty($property_id) ? $property_id : null,
485 'propertystream_town' => !empty($property->location) ? $property->location->__toString() : null,
486 'propertystream_county' => !empty($property->region) ? $property->region->__toString() : null,
487 'propertystream_country' => !empty($property->country) ? $property->country->__toString() : null,
488 'propertystream_display_address' => !empty($property->display_name) ? $property->display_name->__toString() : null,
489 'propertystream_price' => !empty($property->asking_price) ? $property->asking_price->__toString() : null,
490 'propertystream_currency' => !empty($property->currency) ? $property->currency->__toString() : null,
491 'propertystream_price_hide' => !empty($property->price_on_request) ? $property->price_on_request->__toString() : null,
492 'propertystream_sole_agency' => !empty($property->soleAgency) ? $property->soleAgency->__toString() : null,
493 'propertystream_virtualtour' => !empty($property->propertyVideoURL) ? $property->propertyVideoURL->__toString() : null,
494 'propertystream_featured' => !empty($property->featuredProperty) ? $property->featuredProperty->__toString() : null,
495 'propertystream_available_from' => !empty($property->let_next_available) ? self::convert_date($property->let_next_available->__toString()) : null,
496 'propertystream_date_registered' => !empty($property->date_registered) ? self::convert_date($property->date_registered->__toString()) : null,
497 'propertystream_garage_count' => !empty($property->garage_count) ? $property->garage_count->__toString() : null,
498 'propertystream_property_area' => !empty($property->property_area) ? $property->property_area->__toString() : null,
499 'propertystream_internal_area' => !empty($property->internal_area) ? $property->internal_area->__toString() : null,
500 'propertystream_external_area' => !empty($property->external_area) ? $property->external_area->__toString() : null,
501 'propertystream_importer_url' => PSIMPORT_PERRY_PLUGIN_URL,
502 'propertystream_importer' => PSIMPORT_PERRY_PLUGIN_SLUG,
503 ];
504 return $postmeta;
505 }
506
507
508 /**
509 *
510 * @return array $features
511 */
512 final public static function set_features (SimpleXMLElement $property)
513 {
514 $features = [];
515
516 if(!empty($property->features)) {
517 foreach($property->features->item as $feature) {
518 if(empty($feature->Description) || empty($feature->Value)) {
519 continue;
520 }
521 $features[] = [
522 'description' => $feature->Description->__toString(),
523 'value' => $feature->Value->__toString()
524 ];
525 }
526 }
527
528 return $features;
529 }
530
531 /**
532 * Create the core post
533 * @access private
534 * @final
535 * @static
536 */
537 private static function set_post (array $data, $user_id, $property_id)
538 {
539 global $wpdb;
540 $agent_ref = trim($data['AGENT_REF']);
541 $insert = [
542 'post_title' => $agent_ref,
543 'post_content' => $data['DESCRIPTION'],
544 'post_excerpt' => $data['SUMMARY'],
545 'post_type' => 'property',
546 'post_author' => $user_id,
547 'post_status' => 'publish',
548 'post_name' => $data['DISPLAY_ADDRESS'],
549 ];
550 if(!empty($data['PUBLISHED_FLAG'])) {
551 $insert['post_status'] = 'publish';
552 }
553
554 $sql = "SELECT * FROM {$wpdb->prefix}posts WHERE post_title LIKE '%$property_id%'";
555 $exists = $wpdb->get_row($sql);
556 if(!empty($exists)) {
557 $insert['ID'] = $exists->ID;
558 echo "\nUpdating\n";
559 }
560 return wp_insert_post($insert);
561 }
562
563 /**
564 * Set the postmeta for the properties
565 * @access private
566 * @final
567 * @static
568 */
569 private static function set_post_meta ($postmeta, $new_property)
570 {
571 foreach($postmeta as $key => $val) {
572 $nval = $val;
573 if(is_array($val)) {
574 $nval = json_encode($val);
575 }
576 update_post_meta($new_property, strtolower($key), $nval);
577 }
578 }
579
580 /**
581 * Use WP hook to set the required thumbnail sizes
582 * @param array $image_sizes The array of image sizes to generate
583 * @access public
584 * @final
585 * @static
586 * @return array $image_sizes The filtered array
587 */
588 final public static function intermediate_image_sizes( $image_sizes )
589 {
590 // $image_sizes = ['sm'];
591 return $image_sizes;
592 }
593
594 /**
595 * Import and set all of our attachments
596 * @var array $wpdata Our built up array of import data
597 * @access private
598 * @final
599 * @static
600 */
601 private static function set_attachments ($new_property, $property)
602 {
603 update_post_meta($new_property, 'propertystream_images', (array) $property->images->image);
604 update_post_meta($new_property, 'propertystream_site_plans', (array) $property->site_plans->image);
605 update_post_meta($new_property, 'propertystream_epc_certificates', (array) $property->epc_certificates->image);
606 return null;
607 }
608
609 /**
610 * Move old properties not in BLM into the trash
611 * @access public
612 * @final
613 * @static
614 */
615 public static function move_properties_to_trash ($active_properties)
616 {
617 echo "\nProperty deletion starting...";
618 if(empty($active_properties)) {
619 return null;
620 }
621 global $wpdb;
622 $sql = "SELECT ID, post_title FROM {$wpdb->prefix}posts WHERE post_type='property' AND post_title LIKE '%(PERRY)%'";
623 $result = $wpdb->get_results($sql);
624 foreach($result as $row) {
625 if(!in_array($row->ID, $active_properties)) { // for full re-import
626 $result = wp_delete_post( $row->ID, true );
627 echo "\nProperty $row->post_title deleted.";
628 }
629 }
630 echo "\nProperty deletion complete.";
631 return null;
632 }
633
634 /**
635 *
636 * @method convert_date
637 * @access public
638 * @static
639 * @final
640 * @return $date
641 */
642 final public static function convert_date ($date)
643 {
644 $formatted = str_replace('/', '-', $date);
645 $stamped = strtotime($formatted);
646 $newdate = date('Y-m-d H:i:s', $stamped);
647 return $newdate;
648 }
649
650}