Plugin Directory

Changeset 3373689


Ignore:
Timestamp:
10/06/2025 12:42:14 PM (6 months ago)
Author:
PropertyHive
Message:

Update to version 2.1.10

Location:
propertyhive/trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • propertyhive/trunk/README.txt

    r3367847 r3373689  
    44Requires at least: 5.6
    55Tested up to: 6.8.2
    6 Stable tag: 2.1.9
     6Stable tag: 2.1.10
    77License: GPLv3
    88License URI: http://www.gnu.org/licenses/gpl-3.0.html
     
    3939* White label
    4040* Elementor and Divi support
    41 * Yoast and Rank Math compatibility
     41* Yoast, AIOSEO and Rank Math compatibility
    4242* Customisable templates
    4343* Property Hive CRM
     
    182182
    183183== Changelog ==
     184
     185= 2.1.10 - 2025-10-06 =
     186* Added RealEstateListing schema support if using Yoast SEO
     187* Added preliminary support for AIOSEO, including excluded off market properties from XML sitemaps and including RealEstateListing schema
     188* Added commercial description title as CSS class when outputting formatted version so they can be targeted using CSS/JS
     189* Added better support for commercial properties to REST API
    184190
    185191= 2.1.9 - 2025-09-25 =
  • propertyhive/trunk/includes/class-ph-property.php

    r3292381 r3373689  
    820820                if ( !$plain_text )
    821821                {
    822                     $return .= '<p class="description-section">';
     822                    $return .= '<p class="description-section';
     823                    if ($this->{'_description_name_' . $i} != '')
     824                    {
     825                        $return .= ' description-section-' . esc_attr(sanitize_title($this->{'_description_name_' . $i}));
     826                    }
     827                    $return .= '">';
    823828                    if ($this->{'_description_name_' . $i} != '')
    824829                    {
  • propertyhive/trunk/includes/class-ph-rest-api.php

    r3365891 r3373689  
    6060        // Property
    6161        add_filter( 'rest_property_query', array( $this, 'modify_rest_property_query' ), 10, 2 );
     62        add_filter( 'rest_prepare_property', array( $this, 'rest_prepare_property' ), 10, 3 );
    6263        add_action( 'rest_api_init', array( $this, 'register_rest_api_property_fields' ), 99 );
    6364        add_filter( 'rest_property_collection_params', array( $this, 'modify_rest_order_by' ), 10, 1 );
     
    550551            'price_actual',
    551552            'price',
     553            'price_from',
     554            'price_to',
     555            'price_units',
     556            'rent_from',
     557            'rent_to',
     558            'rent_units',
    552559            'price_formatted',
    553560            'rent_frequency',
     
    566573            'parking',
    567574            'outside_space',
     575            'for_sale',
     576            'to_rent',
     577            'floor_area_from',
     578            'floor_area_to',
     579            'floor_area_units',
     580            'site_area_from',
     581            'site_area_to',
     582            'site_area_units',
    568583            'on_market',
    569584            'featured',
     
    602617                        {
    603618                            case "price":
    604                             { 
     619                            {
    605620                                if ( $property->_poa != 'yes' )
    606621                                {
    607                                     if ( $property->_department == 'residential-lettings' ) { $return = $property->_rent; }else{ $return = $property->_price; }
     622                                    $department = $property->_department;
     623                                    if ( ph_get_custom_department_based_on( $department ) !== false )
     624                                    {
     625                                        $department = ph_get_custom_department_based_on( $department );
     626                                    }
     627                                    if ( $department == 'residential-lettings' ) { $return = $property->_rent; }else{ $return = $property->_price; }
    608628                                }
    609                                 else
     629                                break;
     630                            }
     631                            case "price_from":
     632                            case "price_to":
     633                            {
     634                                if ( $property->_price_poa != 'yes' )
    610635                                {
    611                                     $return = '';
     636                                    $return = $property->{'_' . $field_name};
     637                                }
     638                                break;
     639                            }
     640                            case "rent_from":
     641                            case "rent_to":
     642                            {
     643                                if ( $property->_rent_poa != 'yes' )
     644                                {
     645                                    $return = $property->{'_' . $field_name};
    612646                                }
    613647                                break;
     
    10641098    }
    10651099
     1100    public function rest_prepare_property($response, $post, $request)
     1101    {
     1102        // Hide/show fields dynamically per item before it's returned
     1103
     1104        $data = $response->get_data();
     1105
     1106        // Get the department
     1107        $department = $data['department'] ?? get_post_meta($post->ID, '_department', true);
     1108        if ( ph_get_custom_department_based_on( $department ) !== false )
     1109        {
     1110            $department = ph_get_custom_department_based_on( $department );
     1111        }
     1112
     1113        // Define the "not applicable" fields per department
     1114        $remove_for = [
     1115            'residential-sales' => [
     1116                // specify non-sales fields
     1117                'available_date', 'deposit', 'furnished', 'rent_frequency',
     1118                'commercial_tenure', 'commercial_property_type', 'for_sale', 'to_rent', 'price_from', 'price_to', 'price_units', 'rent_from', 'rent_to', 'rent_units', 'floor_area_from', 'floor_area_to', 'floor_area_units', 'site_area_from', 'site_area_to', 'site_area_units'
     1119            ],
     1120            'residential-lettings' => [
     1121                // specify non-lettings fields
     1122                'sale_by', 'tenure',
     1123                'commercial_tenure', 'commercial_property_type', 'for_sale', 'to_rent', 'price_from', 'price_to', 'price_units', 'rent_from', 'rent_to', 'rent_units', 'floor_area_from', 'floor_area_to', 'floor_area_units', 'site_area_from', 'site_area_to', 'site_area_units',
     1124            ],
     1125            'commercial' => [
     1126                // specify non-commercial fields
     1127                'price', 'price_actual', 'bedrooms', 'bathrooms', 'reception_rooms', 'outside_space', 'parking',
     1128                'available_date', 'deposit', 'furnished', 'rent_frequency',
     1129            ],
     1130        ];
     1131
     1132        if ( !empty($remove_for[$department]) )
     1133        {
     1134            foreach ( $remove_for[$department] as $k )
     1135            {
     1136                unset($data[$k]);
     1137            }
     1138        }
     1139
     1140        $response->set_data($data);
     1141
     1142        return $response;
     1143    }
     1144
    10661145    public function register_rest_api_office_fields()
    10671146    {
  • propertyhive/trunk/includes/class-ph-yoast-seo.php

    r2973852 r3373689  
    2727        add_filter( 'manage_edit-property_columns', array( __CLASS__, 'yoast_remove_columns') );
    2828        add_filter( 'wpseo_exclude_from_sitemap_by_post_ids', array( __CLASS__, 'sitemap_exclude_off_market') );
     29       
    2930        add_filter( 'wpseo_schema_webpage_type', array( __CLASS__, 'yoast_schema_webpage_type') );
     31        add_filter( 'wpseo_schema_webpage', array( __CLASS__, 'yoast_schema_webpage') );
     32        add_filter( 'wpseo_schema_graph', array( __CLASS__, 'yoast_schema_graph'), 20 );
     33       
    3034        add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
    3135    }
     
    5660
    5761        return $type;
     62    }
     63
     64    public static function yoast_schema_webpage( $data )
     65    {
     66        // Enrich the WebPage piece with RealEstateListing props (datePosted, offers, mainEntity)
     67
     68        if ( ! is_singular( 'property' ) ) {
     69            return $data;
     70        }
     71
     72        $post_id = get_the_ID();
     73
     74        $property = new PH_Property($post_id);
     75
     76        $url     = get_permalink( $post_id );
     77
     78        // IDs so everything links together nicely in the graph
     79        $residence_id = $url . '#/residence/' . $post_id;
     80        $offer_id     = $url . '#/offer/' . $post_id;
     81
     82        // Core listing bits
     83        $department   = $property->_department;
     84
     85        $data['datePosted'] = date("Y-m-d\TH:i:s", strtotime($property->_on_market_change_date)) . "+00:00";
     86
     87        // Attach an Offer (price, currency, availability) that points at the Residence
     88        if ( $department == 'residential-sales' || ph_get_custom_department_based_on($department) == 'residential-sales' )
     89        {
     90            $data['offers'] = [
     91                '@type'          => 'Offer',
     92                '@id'            => $offer_id,
     93                'price'          => $property->_poa != 'yes' ? (float)$property->_price : '',
     94                'priceCurrency'  => $property->_currency,
     95                // Use a schema.org ItemAvailability URL if you have one; default to InStock
     96                //'availability'   => $availability ?: 'https://schema.org/InStock',
     97                'businessFunction' => 'https://purl.org/goodrelations/v1#Sell',
     98                'itemOffered'    => [ '@id' => $residence_id ],
     99                'url'            => $url
     100            ];
     101        }
     102        elseif ( $department == 'residential-lettings' || ph_get_custom_department_based_on($department) == 'residential-lettings' )
     103        {
     104            $data['offers'] = [
     105                '@type'          => 'Offer',
     106                '@id'            => $offer_id,
     107                'price'          => $property->_poa != 'yes' ? (float)$property->_rent : '',
     108                'priceCurrency'  => $property->_currency,
     109                'priceSpecification' => [
     110                    '@type' => 'UnitPriceSpecification',
     111                    'price' => $property->_poa != 'yes' ? (float)$property->_rent : '',
     112                    'priceCurrency' => $property->_currency,
     113                    'unitText' => $property->_rent_frequency,
     114                ],
     115                'businessFunction' => 'https://purl.org/goodrelations/v1#LeaseOut',
     116                // Use a schema.org ItemAvailability URL if you have one; default to InStock
     117                //'availability'   => $availability ?: 'https://schema.org/InStock',
     118                'itemOffered'    => [ '@id' => $residence_id ],
     119                'url'            => $url
     120            ];
     121        }
     122
     123        // Point the WebPage at the main entity (the actual property)
     124        $data['mainEntity'] = [ '@id' => $residence_id ];
     125
     126        return $data;
     127    }
     128
     129    public static function yoast_schema_graph( $graph )
     130    {
     131        // Append a Residence/House node with all the property specifics
     132
     133        if ( ! is_singular( 'property' ) ) {
     134            return $graph;
     135        }
     136
     137        $post_id = get_the_ID();
     138
     139        $property = new PH_Property($post_id);
     140
     141        $url     = get_permalink( $post_id );
     142
     143        $department   = $property->_department;
     144
     145        $residence_id = $url . '#/residence/' . $post_id;
     146
     147        // Collect property meta
     148        $bedrooms      = (int)$property->_bedrooms;
     149        $bathrooms     = (int)$property->_bathrooms;
     150        $street        = $property->_address_street;
     151        $locality      = $property->_address_two;
     152        $region        = $property->_address_three;
     153        $postcode      = $property->_address_postcode;
     154        $country       = $property->_address_country;
     155        $lat           = $property->_latitude;
     156        $lng           = $property->_longitude;
     157
     158        $images = array();
     159        if ( get_option('propertyhive_images_stored_as', '') == 'urls' )
     160        {
     161            $photo_urls = $property->_photo_urls;
     162            if ( !is_array($photo_urls) ) { $photo_urls = array(); }
     163
     164            if ( !empty($num_images) )
     165            {
     166                $photo_urls = array_slice($photo_urls, 0, $num_images);
     167            }
     168
     169            foreach ( $photo_urls as $photo )
     170            {
     171                $images[] = isset($photo['url']) ? $photo['url'] : '';
     172            }
     173        }
     174        else
     175        {
     176            $gallery_attachments = $property->get_gallery_attachment_ids();
     177
     178            if ( !empty($gallery_attachments) )
     179            {
     180                if ( !empty($num_images) )
     181                {
     182                    $gallery_attachments = array_slice($gallery_attachments, 0, $num_images);
     183                }
     184           
     185                foreach ($gallery_attachments as $gallery_attachment)
     186                {
     187                    $images[] = wp_get_attachment_url( $gallery_attachment );
     188                }
     189            }
     190        }
     191        $images = array_values( array_unique( array_filter( $images ) ) );
     192
     193        $types = array( 'Residence' );
     194        if ( $department != 'commercial' && ph_get_custom_department_based_on($department) != 'commercial' )
     195        {
     196            $types[] = 'SingleFamilyResidence';
     197        }
     198        $residence = [
     199            '@type' => $types,
     200            '@id'   => $residence_id,
     201            'url'   => $url,
     202            'name'  => get_the_title( $post_id ),
     203        ];
     204
     205        // Address
     206        if ( $street || $locality || $region || $postcode || $country ) {
     207            $residence['address'] = array_filter( [
     208                '@type'           => 'PostalAddress',
     209                'streetAddress'   => $street,
     210                'addressLocality' => $locality,
     211                'addressRegion'   => $region,
     212                'postalCode'      => $postcode,
     213                'addressCountry'  => $country,
     214            ] );
     215        }
     216
     217        // Geo
     218        if ( $lat && $lng ) {
     219            $residence['geo'] = [
     220                '@type'     => 'GeoCoordinates',
     221                'latitude'  => (float)$lat,
     222                'longitude' => (float)$lng,
     223            ];
     224        }
     225
     226        // Rooms
     227        if ( $bedrooms && $department != 'commercial' && ph_get_custom_department_based_on($department) != 'commercial' )  { $residence['numberOfBedrooms']      = $bedrooms; }
     228        if ( $bathrooms && $department != 'commercial' && ph_get_custom_department_based_on($department) != 'commercial' ) { $residence['numberOfBathroomsTotal'] = $bathrooms; }
     229
     230        // Photos / primary image
     231        if ( $images ) {
     232            $residence['image'] = $images;
     233        }
     234
     235        $graph[] = $residence;
     236        return $graph;
    58237    }
    59238
  • propertyhive/trunk/propertyhive.php

    r3367847 r3373689  
    44 * Plugin URI: https://wordpress.org/plugins/propertyhive/
    55 * Description: Property Hive has everything you need to build estate agency websites
    6  * Version: 2.1.9
     6 * Version: 2.1.10
    77 * Author: PropertyHive
    88 * Author URI: https://wp-property-hive.com
     
    2828    *
    2929    * @class PropertyHive
    30     * @version 2.1.9
     30    * @version 2.1.10
    3131    */
    3232    final class PropertyHive {
     
    3535         * @var string
    3636         */
    37         public $version = '2.1.9';
     37        public $version = '2.1.10';
    3838         
    3939        /**
     
    305305            include_once( 'includes/class-ph-yoast-seo.php' );              // Yoast SEO
    306306            include_once( 'includes/class-ph-rank-math.php' );              // Rank Math
     307            include_once( 'includes/class-ph-aioseo.php' );                 // All In One SEO
    307308            include_once( 'includes/class-ph-duplicate-post.php' );         // Duplicate Post
    308309
Note: See TracChangeset for help on using the changeset viewer.