0

plugins/idx-broker-platinum/idx/shortcodes/register-impress-shortcodes.php
This is the plugin file where I need to use a filter to override the structure.
Filter name:

impress_showcase_property_html

class Register_Impress_Shortcodes

<?php

/**
 * Property_showcase_shortcode function.
 *
 * @access public
 * @param array $atts (default: array())
 * @return void
 */
public function property_showcase_shortcode( $atts = array() ) {
    extract(
        shortcode_atts(
            array(
                'max'           => 4,
                'use_rows'      => 1,
                'num_per_row'   => 4,
                'show_image'    => 1,
                'order'         => 'default',
                'property_type' => 'featured',
                'saved_link_id' => '',
                'agent_id'      => '',
                'styles'        => 1,
                'new_window'    => 0,
                'colistings'    => 1,
            ),
            $atts
        )
    );

    if ( ! empty( $styles ) ) {
        wp_enqueue_style( 'impress-showcase' );
    }

    $output = '';
    if ( ( $property_type ) === 'savedlinks' ) {
        $properties = $this->idx_api->saved_link_properties( $saved_link_id );
        $output    .= '<!-- Saved Link ID: ' . $saved_link_id . ' -->';
    } else {
        $properties = $this->idx_api->client_properties( $property_type );
        $output    .= '<!-- Property Type: ' . $property_type . ' -->';
    }

    // Force type as Array.
    $properties = json_encode( $properties );
    $properties = json_decode( $properties, true );

    // If no properties or an error, load message
    if ( empty( $properties ) || ( isset( $properties[0] ) && $properties[0] === 'No results returned' ) || isset( $properties['errors']['idx_api_error'] ) ) {
        if ( isset( $properties['errors']['idx_api_error'] ) ) {
            return $output .= '<p>' . $properties['errors']['idx_api_error'][0] . '</p>';
        } else {
            return $output .= '<p>No properties found</p>';
        }
    }

    $total = count( $properties );
    $count = 0;

    $column_class = '';

    if ( 1 == $use_rows ) {
        // Max of four columns
        $number_columns = ( $num_per_row > 4 ) ? 4 : (int) $num_per_row;

        // column class
        switch ( $number_columns ) {
            case 0:
                $column_class = 'columns small-12 large-12';
                break;
            case 1:
                $column_class = 'columns small-12 large-12';
                break;
            case 2:
                $column_class = 'columns small-12 medium-6 large-6';
                break;
            case 3:
                $column_class = 'columns small-12 medium-4 large-4';
                break;
            case 4:
                $column_class = 'columns small-12 medium-3 large-3';
                break;
        }
    }

    if ( ! isset( $new_window ) ) {
        $new_window = 0;
    }

    $target = $this->target( $new_window );

    if ( 'low-high' == $order ) {
        // sort low to high
        usort( $properties, array( $this->idx_api, 'price_cmp' ) );
    }

    if ( 'high-low' == $order ) {
        usort( $properties, array( $this->idx_api, 'price_cmp' ) );
        $properties = array_reverse( $properties );
    }

    // Used to hold agent data when matching for colistings.
    $agent_data;

    foreach ( $properties as $prop ) {

        if ( ! empty( $agent_id ) ) {
            // Check if listing agent ID matches agent's IDX ID.
            if ( empty( $prop['userAgentID'] ) || (int) $agent_id !== (int) $prop['userAgentID'] ) {
                // If colistings is enabled, check for match.
                if ( $colistings ) {
                    if ( array_key_exists( 'coListingAgentID', $prop ) ) {
                        // Check if $agent_data is already set, if not grab a new copy to get MLS-provided agent ID.
                        if ( empty( $agent_data ) ) {
                            $agent_data = $this->idx_api->idx_api( 'agents?filterField=agentID&filterValue=' . $agent_id, IDX_API_DEFAULT_VERSION, 'clients', [], 7200, 'GET', true );
                        }
                        // Check the listing's coListingAgentID against the agent's raw MLS-provided ID, continues if no match.
                        if ( empty( $agent_data['agent'][0]['listingAgentID'] ) || $agent_data['agent'][0]['listingAgentID'] !== $prop['coListingAgentID'] ) {
                            continue;
                        }
                    } else {
                        // Listing does not have coListingAgentID field data to match against.
                        continue;
                    }
                } else {
                    // Colistings setting is not enabled.
                    continue;
                }
            }
        }

        if ( ! empty( $max ) && $count == $max ) {
            return $output;
        }

        $prop_image_url = $prop['image']['0']['url'] ?? $prop['image']['1']['url'] ?? plugins_url( '/idx-broker-platinum/assets/images/noPhotoFull.png' );

        if ( 1 == $use_rows && $count == 0 && $max != '1' ) {
            $output .= '<div class="shortcode impress-property-showcase impress-row">';
        }

        if ( empty( $prop['propStatus'] ) ) {
            $prop['propStatus'] = 'none';
        }

        $count++;

        // Add Disclaimer when applicable.
        if ( isset( $prop['disclaimer'] ) && ! empty( $prop['disclaimer'] ) ) {
            foreach ( $prop['disclaimer'] as $disclaimer ) {
                if ( in_array( 'widget', $disclaimer ) ) {
                    $disclaimer_text = $disclaimer['text'];
                    $disclaimer_logo = $disclaimer['logoURL'];
                }
            }
        }
        // Add Courtesy when applicable.
        if ( isset( $prop['courtesy'] ) && ! empty( $prop['courtesy'] ) ) {
            foreach ( $prop['courtesy'] as $courtesy ) {
                if ( in_array( 'widget', $courtesy ) ) {
                    $courtesy_text = $courtesy['text'];
                }
            }
        }

        $prop = $this->set_missing_core_fields( $prop );

        // Get URL and add suffix if one exists
        if ( isset( $prop['fullDetailsURL'] ) ) {
            $url = $prop['fullDetailsURL'];
        } else {
            $url = $this->idx_api->details_url() . '/' . $prop['detailsURL'];
        }

        if ( has_filter( 'impress_showcase_property_url_suffix' ) ) {
            $url = $url . apply_filters( 'impress_showcase_property_url_suffix', $suffix = http_build_query( array() ), $prop, $this->idx_api );
        }

        if ( 1 == $show_image ) {
            $output .= apply_filters(
                'impress_showcase_property_html',
                sprintf(
                    '<div class="impress-showcase-property %17$s">
                    <a href="%3$s" class="impress-showcase-photo" target="%18$s">
                        <img src="%4$s" alt="%5$s" title="%6$s %7$s %8$s %9$s %10$s, %11$s" />
                        <span class="impress-price">%1$s</span>
                        <span class="impress-status">%2$s</span>
                        <p class="impress-address">
                            <span class="impress-street">%6$s %7$s %8$s %9$s</span>
                            <span class="impress-cityname">%10$s</span>,
                            <span class="impress-state"> %11$s</span>
                        </p>
                    </a>
                    <p class="impress-beds-baths-sqft">
                    %12$s
                    %13$s
                    %14$s
                    %15$s
                    </p>
                    %16$s
                    </div>',
                    price_selector( $prop ),
                    $prop['propStatus'],
                    $url,
                    $prop_image_url,
                    htmlspecialchars( $prop['remarksConcat'] ),
                    $prop['streetNumber'],
                    $prop['streetDirection'],
                    $prop['streetName'],
                    $prop['unitNumber'],
                    $prop['cityName'],
                    $prop['state'],
                    $this->hide_empty_fields( 'beds', 'Beds', ( empty( $prop['bedrooms'] ) ? '' : $prop['bedrooms'] ) ),
                    $this->hide_empty_fields( 'baths', 'Baths', ( empty( $prop['totalBaths'] ) ? '' : $prop['totalBaths'] ) ),
                    $this->hide_empty_fields( 'sqft', 'SqFt', ( empty( $prop['sqFt'] ) ? '' : $prop['sqFt'] ) ),
                    $this->hide_empty_fields( 'acres', 'Acres', ( empty( $prop['acres'] ) ? '' : $prop['acres'] ) ),
                    $this->maybe_add_disclaimer_and_courtesy( $prop ),
                    $column_class,
                    $target
                ),
                $prop,
                ( isset( $instance ) ? $instance : [] ),
                $url,
                $prop_image_url,
                $this->maybe_add_disclaimer_and_courtesy( $prop ),
                $column_class,
                $target
            );
        } else {
            $output .= apply_filters(
                'impress_showcase_property_list_html',
                sprintf(
                    '<li class="impress-showcase-property-list %13$s">
                    <a href="%2$s" target="%14$s">
                        <p>
                            <span class="impress-price">%1$s</span>
                            <span class="impress-address">
                                <span class="impress-street">%3$s %4$s %5$s %6$s</span>
                                <span class="impress-cityname">%7$s</span>,
                                <span class="impress-state"> %8$s</span>
                            </span>
                            <span class="impress-beds-baths-sqft">
                                %9$s
                                %10$s
                                %11$s
                                %12$s
                            </span>
                        </p>
                    </a>
                </li>',
                    price_selector( $prop ),
                    $url,
                    $prop['streetNumber'],
                    $prop['streetDirection'],
                    $prop['streetName'],
                    $prop['unitNumber'],
                    $prop['cityName'],
                    $prop['state'],
                    $this->hide_empty_fields( 'beds', 'Beds', ( empty( $prop['bedrooms'] ) ? '' : $prop['bedrooms'] ) ),
                    $this->hide_empty_fields( 'baths', 'Baths', ( empty( $prop['totalBaths'] ) ? '' : $prop['totalBaths'] ) ),
                    $this->hide_empty_fields( 'sqft', 'SqFt', ( empty( $prop['sqFt'] ) ? '' : $prop['sqFt'] ) ),
                    $this->hide_empty_fields( 'acres', 'Acres', ( empty( $prop['acres'] ) ? '' : $prop['acres'] ) ),
                    $column_class,
                    $target
                ),
                $prop,
                ( isset( $instance ) ? $instance : [] ),
                $url,
                $column_class,
                $target
            );
        }

        if ( 1 == $use_rows && ( 1 !== $count || 1 === $total ) ) {

            // close a row if..
            // num_per_row is a factor of count OR
            // count is equal to the max number of listings to show OR
            // count is equal to the total number of listings available
            if ( $count % $num_per_row == 0 || $count == $total || $count == $max ) {
                $output .= '</div> <!-- .impress-row -->';
            }

            // open a new row if..
            // num per row is a factor of count AND
            // count is not equal to max AND
            // count is not equal to total
            if ( $count % $num_per_row == 0 && $count != $max && $count != $total ) {
                $output .= '<div class="impress-row shortcode impress-property-showcase">';
            }
        }
    }

    return $output;

}

I can not understand how to override $this in functions PHP. what is the proper way to do that?

Added filter code to my functions.php

add_filter('impress_showcase_property_html', 'impress_showcase_property_html_callback', 10, 8);

if(!function_exists('impress_showcase_property_html_callback')) {
    /**
     * Update Layout
     * @param $prop
     * @param $url
     * @param $prop_image_url
     * @param $column_class
     * @param $target
     *
     * @return string
     */
    function impress_showcase_property_html_callback($value, $prop, $instance, $url, $prop_image_url, $column_class, $target){

        $value = sprintf(
            '<div class="impress-showcase-property %17$s">
                        <a href="%3$s" class="impress-showcase-photo" target="%18$s">
                            <img src="%4$s" alt="%5$s" title="%6$s %7$s %8$s %9$s %10$s, %11$s" />
                            <span class="impress-price">%1$s</span>
                            <span class="impress-status">%2$s</span>
                        </a>
                        <p class="impress-address">
                            <span class="impress-street">%6$s %7$s %8$s %9$s</span>
                            <span class="impress-cityname">%10$s</span>,
                            <span class="impress-state"> %11$s</span>
                        </p>                        
                        <p class="impress-beds-baths-sqft">
                        %12$s
                        %13$s
                        %14$s
                        %15$s
                        </p>
                        %16$s
                        </div>',
            price_selector( $prop ),
            $prop['propStatus'],
            $url,
            $prop_image_url,
            htmlspecialchars( $prop['remarksConcat'] ),
            $prop['streetNumber'],
            $prop['streetDirection'],
            $prop['streetName'],
            $prop['unitNumber'],
            $prop['cityName'],
            $prop['state'],
            $this->hide_empty_fields( 'beds', 'Beds', ( empty( $prop['bedrooms'] ) ? '' : '<span class="numbers">'.$prop['bedrooms'].'</span>' ) ),
            $this->hide_empty_fields( 'baths', 'Baths', ( empty( $prop['totalBaths'] ) ? '' : '<span class="numbers">'.$prop['totalBaths'].'</span>' ) ),
            $this->hide_empty_fields( 'sqft', 'SqFt', ( empty( $prop['sqFt'] ) ? '' : '<span class="numbers">'.$prop['sqFt'].'</span>' ) ),
            $this->hide_empty_fields( 'acres', 'Acres', ( empty( $prop['acres'] ) ? '' : '<span class="numbers">'.$prop['acres'].'</span>' ) ),
            $this->maybe_add_disclaimer_and_courtesy( $prop ),
            $column_class,
            $target
        );
        return $value;
    }
}
8
  • What do you mean by "override $this"? If you just want to modify the shortcode output, then just hook your function on the impress_showcase_property_html filter and modify the HTML to your liking.
    – Sally CJ
    Feb 25, 2023 at 6:49
  • @SallyCJ How can I do that? it's getting an error with $this->function_name();
    – Ravi
    Feb 25, 2023 at 7:01
  • Does my answer help? If not, how/when/where did you call add_filter()?
    – Sally CJ
    Feb 25, 2023 at 7:34
  • @SallyCJ Apology to forgot to add filter code, please check the add_filter function now. $this->hide_empty_fields() and $this->maybe_add_disclaimer_and_courtesy( $prop ) is not working because it is another class method which coming from the plugins code.
    – Ravi
    Feb 25, 2023 at 9:31
  • Well in that case, what is the full code in that Register_Impress_Shortcodes class? Does it have a global instance like global $class; $class = new Register_Impress_Shortcodes();? Are those two methods (hide_empty_fields() and maybe_add_disclaimer_and_courtesy()) public, protected or maybe private?
    – Sally CJ
    Feb 25, 2023 at 9:56

1 Answer 1

1

So you're trying to call the hide_empty_fields() and maybe_add_disclaimer_and_courtesy() methods in the Register_Impress_Shortcodes class, from within a global function, and it's not impossible to call class methods from within such global functions, but you cannot use $this in your function because $this is only available from within a class method which is called from within an object context. More details in the PHP manual

As for the proper way to call those two class methods from within your function, I'm not sure (unless maybe, if you provide the full class code and the information on how/when/where it's being instantiated), but see below for some options that you can try, without modifying the core plugin files:

  • If those methods are public and there's an instance of the class in the global scope, e.g. global $Register_Impress_Shortcodes; $Register_Impress_Shortcodes = new Register_Impress_Shortcodes();, then just add global $Register_Impress_Shortcodes; to your function (at the top), then replace those $this with $Register_Impress_Shortcodes.

  • If such global instance is not available, but those methods are public and there is a "static instance getter" like the DBConn::getConn() here, then in your function, just replace the $this with Register_Impress_Shortcodes::instance() (or replace instance with the correct method name).

    If such method doesn't exist, but/or the plugin in question provides a global function like register_impress_shortcodes_instance(), which returns the class instance, then replace those $this with register_impress_shortcodes_instance().

  • If those methods are not public or there's no global class instance, and neither an instance getter method or function, and that the Register_Impress_Shortcodes class can be extended, and also that those methods are not private, then you can do something like this:

    <?php
    // Extend the class.
    class My_Register_Impress_Shortcodes extends Register_Impress_Shortcodes {
        public function __construct() {
            // Add your filter.
            add_filter( 'impress_showcase_property_html', array( $this, 'impress_showcase_property_html_callback' ), 10, 7 );
        }
    
        // Now this is your filter callback which is a method in this class. So
        // you can now use $this and access the methods hide_empty_fields() and
        // maybe_add_disclaimer_and_courtesy() defined in the parent class.
        public function impress_showcase_property_html_callback( $value, $prop, $instance, $url, $prop_image_url, $column_class, $target ) {
            $value = sprintf(
                '... your code here',
                price_selector( $prop ),
                $prop['propStatus'],
                $url,
                $prop_image_url,
                htmlspecialchars( $prop['remarksConcat'] ),
                $prop['streetNumber'],
                $prop['streetDirection'],
                $prop['streetName'],
                $prop['unitNumber'],
                $prop['cityName'],
                $prop['state'],
                parent::hide_empty_fields( 'beds', 'Beds', ( empty( $prop['bedrooms'] ) ? '' : '<span class="numbers">'.$prop['bedrooms'].'</span>' ) ),
                parent::hide_empty_fields( 'baths', 'Baths', ( empty( $prop['totalBaths'] ) ? '' : '<span class="numbers">'.$prop['totalBaths'].'</span>' ) ),
                parent::hide_empty_fields( 'sqft', 'SqFt', ( empty( $prop['sqFt'] ) ? '' : '<span class="numbers">'.$prop['sqFt'].'</span>' ) ),
                parent::hide_empty_fields( 'acres', 'Acres', ( empty( $prop['acres'] ) ? '' : '<span class="numbers">'.$prop['acres'].'</span>' ) ),
                parent::maybe_add_disclaimer_and_courtesy( $prop ),
                $column_class,
                $target
            );
    
            return $value;
        }
    }
    
    function init_my_register_impress_shortcodes() {
        new My_Register_Impress_Shortcodes();
    }
    add_action( 'init', 'init_my_register_impress_shortcodes' );
    

    Note: Be sure to remove the add_filter('impress_showcase_property_html', 'impress_showcase_property_html_callback', 10, 8); in your code.

  • If the class cannot be extended or you're having trouble calling those methods from within your class, then I guess you would want to unregister/remove the shortcode added by that class/plugin, then copy that very class, rename it and re-add the shortcode you have removed.

    That way, you wouldn't need to hook on impress_showcase_property_html and simply modify the shortcode output in the property_showcase_shortcode() method...

    But the problem with this (and the previous option), is that when the plugin is updated, you would need to revise your class/methods so that it's in sync with the latest code in the updated plugin.

Another option that you can try, is if possible, create 2 global functions (e.g. my_hide_empty_fields() and my_maybe_add_disclaimer_and_courtesy()) which does what those methods do, respectively, i.e. basically copy the code in those methods... and edit it accordingly, e.g. remove any $this calls. Then just use your functions from within your impress_showcase_property_html_callback() function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.