Ask the community

This is a community support forum where you can ask
questions and interact with other PremiumPress Customers.

Listings Widget sorted by distance

  • Sophie
    Sophie
    Newbie 12 points
    June 6, 2015 at 12:07 am

    Hi Everyone,

    I am trying to sort the listings in the Listings widget in distance order. I tried to add “&orderby=distance&order=asc” in the query but it’s not working.

    What would be even better is if when viewing a single listing, I could sort the ones showed in the widget in distance order in relation with the location of the single listing being showed. In other words, it would show other listings in the same area.

    Anybody has any idea how to achieve this?

    Thanks

  • Sophie
    Sophie
    Newbie 12 points
    June 9, 2015 at 10:28 pm

    Anyone?
    I’m actually surprised nobody felt the need for such a feature before. Am I missing something?

  • zarko
    zarko
    Senior Member 360 points
    June 9, 2015 at 10:45 pm

    hi Sophie,

    Do you mean listings widget from Appearance > Widgets?

    Possible problem with this could be that global order by query has priority, try changing order from General setup > Search Results Page in Display Order dropdown just to see if order of your listings widget is going to change

  • Sophie
    Sophie
    Newbie 12 points
    June 9, 2015 at 11:23 pm

    Hi Zarko,

    Thanks for your answer. My Display Order in Search Results Page section is set to “System Set (no default order) so I’m assuming it should not interfere. Although I tried changing it to other settings and it does make a difference in the listing order in the widget.

    I tracked the distance sorting down to the _distinct_sql() function in the class_core.php file. I tried adding the following lines to it:

    [code title=””] if( isset($GLOBALS[‘flag-single’]) && $post->post_type == THEME_TAXONOMY.”_type” ) {
    $lat=strip_tags(get_post_meta($post->ID,’map-lat’,true));
    $log=strip_tags(get_post_meta($post->ID,’map-log’,true));

    if(strlen($lat)>0 && strlen($log)>0){
    return “DISTINCT $wpdb->posts.ID, 3956 * 2 * ASIN(SQRT( POWER(SIN((t1.meta_value – “.$lat.” ) * pi()/180 / 2), 2) +COS(t1.meta_value * pi()/180) * COS(“.$lat.” * pi()/180) * POWER(SIN((t2.meta_value – “.$log.”) * pi()/180 / 2), 2) )) as distance, “;
    }
    }
    [/code]

    The IF statement got triggered when viewing a single listing, but WP_Query returned an empty result in the widget…

    I have a feeling I’m close to the solution here, but just not quite there…

  • Sophie
    Sophie
    Newbie 12 points
    June 10, 2015 at 4:19 am

    Ok, I found the solution. Here it is in case someone wants to use it in the future:

    No need to modify the class_core.php file. Instead I modified the class_widgets.php file to suit my needs.

    I ended up using a custom SELECT query instead of WP_Query. Under the core_widgets_listings class that starts at line 994, I modified the widget() function so that it starts like this:

    [code title=””] function widget($args, $instance) {
    global $CORE, $post, $wp_query, $wpdb; $STRING = “”; $image = “”; @extract($args);

    $user_lat = strip_tags(get_post_meta($post->ID,’map-lat’,true));
    $user_long = strip_tags(get_post_meta($post->ID,’map-log’,true));

    $the_posts = $wpdb->get_results(“SELECT p.*, pm1.meta_value as lat, pm2.meta_value as lon,
    ACOS(SIN(RADIANS($user_lat))*SIN(RADIANS(pm1.meta_value))+COS(RADIANS($user_lat))*COS(RADIANS(pm1.meta_value))*COS(RADIANS(pm2.meta_value)-RADIANS($user_long))) * 3959 AS distance
    FROM $wpdb->posts p
    INNER JOIN $wpdb->postmeta pm1 ON p.id = pm1.post_id AND pm1.meta_key = ‘map-lat’
    INNER JOIN $wpdb->postmeta pm2 ON p.id = pm2.post_id AND pm2.meta_key = ‘map-log’
    WHERE post_type = ‘listing_type’ AND post_status = ‘publish’
    ORDER BY distance ASC
    LIMIT 5;”);

    // CHECK WE HAVE RESULTS
    if(count($the_posts) > 0 ){ //meta_value_num

    // 1. DISPLAY TITLE
    echo “<div class=’core_widgets_listings’>”.$before_widget.$before_title.$instance[‘title’];

    // 2. AFTER TITLE
    echo “</div>”;

    // 3. LISTINGS
    echo “<ul class=’list-group’>”;

    $GLOBALS[‘IS_WIDGET’] = TRUE;
    foreach($the_posts as $wpost){
    if($wpost->ID == $post->ID) { continue; }

    if(isset($instance[‘image’]) && $instance[‘image’] == 1){

    [/code]

    The rest of the widget function is the same as the original except that $post needs to be changed to $wpost.

    This will display the 4 closest listings to the one being on display on the single listing page. To change this, simply change LIMIT 5 to the desired number +1.

    I think this new widget is very useful. I’m using it with the new Business Directory Theme but I think it could be appreciated in other themes such as the Real Estate WordPress Theme where nearby houses for sale could be shown when viewing a single house listing.

    This coding is not the most elegant but it does the job. I know it’s not the best habit to modify the core files of the theme since they might get overwritten in a future theme update but I didn’t see any other alternative.

    Enjoy and feel free to comment if you have a better solution.

  • zarko
    zarko
    Senior Member 360 points
    June 10, 2015 at 11:06 pm

    Thanks for sharing this Sophie :)

    Just I would create this in child theme or a plugin If I were you so it doesn’t get overwritten after theme updates.

    You can just copy entire widget class [code title=””]class core_widgets_listings[/code] , rename its name to something like [code title=””]class core_widgets_listings_new[/code] and use register widget function to register it. Code can be used either in child theme or in plugin

  • Sophie
    Sophie
    Newbie 12 points
    June 11, 2015 at 3:21 am

    Great idea, thanks Zarko!

  • Paul
    Paul
    Newbie 74 points
    June 11, 2015 at 10:17 pm

    this is very helpful, do i copy your code and insert it from line 994?
    Can this be made category specific too?

  • Sophie
    Sophie
    Newbie 12 points
    June 12, 2015 at 3:18 am

    @Paul
    Assuming you have version 8.2 of Business Directory Theme:

    1- replace lines 1053 to 1086 of the class_widget.php file with the code I previously posted
    2- from line 1087 to 1092 replace every instance of $post with $wpost.

    Obviously after this, you should only use this widget on the single listing page OR like Zarko suggested, make a whole new widget if you are familiar enough with php.

    Sure it can be made category specific, I don’t have a way of testing this right now but you could try replacing the SELECT statement with something like this:

    [code title=””]SELECT p.*, pm1.meta_value as lat, pm2.meta_value as lon,
    ACOS(SIN(RADIANS($user_lat))*SIN(RADIANS(pm1.meta_value))+COS(RADIANS($user_lat))*COS(RADIANS(pm1.meta_value))*COS(RADIANS(pm2.meta_value)-RADIANS($user_long))) * 3959 AS distance
    FROM $wpdb->posts p
    INNER JOIN $wpdb->postmeta pm1 ON p.id = pm1.post_id AND pm1.meta_key = ‘map-lat’
    INNER JOIN $wpdb->postmeta pm2 ON p.id = pm2.post_id AND pm2.meta_key = ‘map-log’
    LEFT JOIN $wpdb->post2cat ON ($wpdb->posts.ID = $wpdb->post2cat.post_id) WHERE post_type = ‘listing_type’ AND post_status = ‘publish’ AND $wpdb->post2cat.category_id == $catid
    ORDER BY distance ASC
    LIMIT 5;[/code]

    Just make sure that the $catid variable contains the category ID (numeric) that you want the widget to be applied to. Like I said, I did not test this, so hopefully it will work.

  • Paul
    Paul
    Newbie 74 points
    June 12, 2015 at 7:26 am

    Wow thanks for that Sophie! great help


  • Josh
    Super Guru 13,885 points
    June 12, 2015 at 1:03 pm

    Thanks for sharing Sophie :)

  • Paul
    Paul
    Newbie 74 points
    June 13, 2015 at 5:15 pm

    Ive tried to implement this as a widget by following some guides online about creating your own widget plugin, but I’m completely baffled, I’m really struggling to understand how wordpress works! would anyone be able to give me a little help with this? its something i really want as a feature on my site but id rather it was a plugin so i can still have updates, I’ve requested estimates for someone to do this for me via the link on here and the estimates are $750!!

    All i’d like is a side bar widget plugin which will list accommodation nearby and only show on a listing page. I’ve tried to use the existing widgets with a query string to no avail, surely this is something that won’t cost $750!

    Any takers?

  • Sophie
    Sophie
    Newbie 12 points
    June 14, 2015 at 1:21 pm

    One more thing, I forgot to add this line as a safety to make sure the widget only appears on a single listing page:

    [code title=””] if(!isset($GLOBALS[‘flag-single’]) || ( isset($GLOBALS[‘flag-single’]) && $post->post_type != THEME_TAXONOMY.”_type” )){ return; }
    [/code]

    This should be right after the second line of my previously posted code.

    @Paul: I’ll see what I can do when I have a minute.

  • Paul
    Paul
    Newbie 74 points
    June 14, 2015 at 1:40 pm

    Thank you Sophie, id be forever grateful :)

  • Sophie
    Sophie
    Newbie 12 points
    June 14, 2015 at 5:31 pm

    Well I guess my work was not complete until I made this into a standalone plugin. This way no need to modify any of the theme files.

    So here it is. Just unzip it in your plugins folder.
    Enjoy :)

    Attachments:
    You must be logged in to view attached files.
Viewing 15 posts - 1 through 15 (of 27 total)