Add counters to listings and display verified contact information

Hey,

I was browsing some existing classified sites for inspiration and made notes of some features that would be nice to see implemented in HivePress eventually.

  1. A last updated counter - (e.g. :counterclockwise_arrows_button: Last updated: 40 days ago)
  2. A creation date/day counter - (e.g. :date: Created 58 days ago)
  3. An expiration counter - (e.g. :hourglass_not_done: Expires in 6 days)

Regarding these counters, it would also be nice if we could choose the position of these. For example, the option to add them under ‘Report Listing’ and ‘Write a Review’, near the existing Geolocation, date added, star-rating summary. or at the end of the listing information/tags, etc.

Another neat addition that I seen on some other sites was a small badge that indicated if a user had either verified their phone number and/or email address. Doing so, could add elements like this:

:white_check_mark: Email Verified
:white_check_mark: Phone Verified

side note: Once a user is Phone verified, perhaps they could also log in using their phone number?

While I’ve seen others in the community talk about adding their own custom solution (which I’ve also now implemented myself) - it would be nice if HivePress offered an official Social Sharing extension that allows visitors to easily share the listing they’re currently viewing.

Cheers,
Chris :victory_hand:

Offical social sharing extension:

The counters are easily done with some hooks/code snippets.

Email is already verified on registration if enabled.
Phone verification requires you to send an sms trrough some service provider in order to be able to validate the number.

1 Like

Thanks for your reply, JSHBV. However, I already use the Social Links extension that you linked to. This is not what I mean.

The extension you linked to allows users to easily add links to their social accounts. What I’m trying to describe is a ‘Share via …’ extension, that grabs the listing title and URL then provides options to share the current listing that’s being viewed via WhatsApp, Facebook, etc.

I have already added what I’m describing through a custom implementation, but it would be nice to eventually see an official extension from HivePress.

I don’t doubt the counters would be fairly easy to add, but my coding knowledge and free time are extremely limited.

Yes, email verification can be enabled, but I’m talking about adding ‘trust factors’ to listing/profile pages, so other users can easily tell if a vendor is email/phone verified.

The phone verification part seems like the most difficult/time-consuming part to set up.

I couldn’t resist having a go at this myself and after a few attempts have achieved the counters.

Replace the default ‘Added on’ label and stylize the new counters with this CSS:

/* Hide the default 'added' label */
time.hp-listing__created-date.hp-listing__date.hp-meta {
    display: none;
}

/* Style the custom counters container */
.custom-counters {
    display: flex;
    flex-direction: row; /* Default: row for larger screens */
    gap: 15px; /* Space between counters */
    margin-bottom: 10px; /* Space below the counters */
}

/* Style each counter */
.custom-counter {
    display: flex;
    align-items: center; /* Vertically center icon and text */
    font-size: 11px;
    color: #666;
    text-transform: uppercase;
    letter-spacing: 1px;
}

/* Style the icons within counters */
.custom-counter i {
    margin-right: 5px; /* Space between icon and text */
    width: 16px; /* Fixed width for icon alignment */
    text-align: center;
    color: #C1C8D5; /* Light gray color for icons */
}

/* Media query for mobile devices */
@media (max-width: 600px) {
    .custom-counters {
        flex-direction: column; /* Stack counters vertically on mobile */
        gap: 5px; /* Reduce gap for mobile */
    }
}

Add this via Code Snippets plugin:


// Enqueue Font Awesome only on individual listing pages
add_action( 'wp_enqueue_scripts', function() {
    if ( is_singular( 'hp_listing' ) ) {
        wp_enqueue_style( 'font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', [], '5.15.4' );
    }
});

// Add custom counters to the listing_details_primary block
add_filter(
    'hivepress/v1/templates/listing_view_page/blocks',
    function( $blocks, $template ) {
        global $post;
        $listing_id = $post->ID;

        // Get the listing model
        $listing = \HivePress\Models\Listing::query()->get_by_id( $listing_id );
        if ( ! $listing ) {
            return $blocks; // Return unchanged blocks if listing is not found
        }

        // Get timestamps (using site's timezone)
        $created_time = get_post_time( 'U', true, $listing_id );
        $updated_time = get_post_modified_time( 'U', true, $listing_id );
        $expiration_time = $listing->get_expired_time(); // Unix timestamp from hp_expired_time
        $current_time = current_time( 'timestamp' ); // Current time in site's timezone

        // Calculate time differences
        $created_diff = human_time_diff( $created_time, $current_time );
        $updated_diff = human_time_diff( $updated_time, $current_time );

        // Handle expiration
        if ( $expiration_time ) {
            if ( $expiration_time > $current_time ) {
                $time_diff = human_time_diff( $current_time, $expiration_time );
                $expires_text = 'Expires in ' . $time_diff;
                $icon = 'fa-hourglass-half';
            } else {
                $time_diff = human_time_diff( $expiration_time, $current_time );
                $expires_text = 'Expired ' . $time_diff . ' ago';
                $icon = 'fa-hourglass-end';
            }
        } else {
            $expires_text = 'N/A';
            $icon = 'fa-hourglass-end';
        }

        // Generate HTML for counters
        $counter_html = '
        <div class="custom-counters">
            <div class="custom-counter"><i class="fas fa-clock"></i> Created ' . esc_html( $created_diff ) . ' ago</div>
            <div class="custom-counter"><i class="fas fa-sync-alt"></i> Updated ' . esc_html( $updated_diff ) . ' ago</div>
            <div class="custom-counter"><i class="fas ' . esc_attr( $icon ) . '"></i> ' . esc_html( $expires_text ) . '</div>
        </div>
        ';

        // Merge the custom block into the template
        $blocks = hivepress()->helper->merge_trees(
            [ 'blocks' => $blocks ],
            [
                'blocks' => [
                    'listing_details_primary' => [
                        'blocks' => [
                            'test_output_details' => [
                                'type'    => 'content',
                                'content' => $counter_html,
                                '_order'  => 10,
                            ],
                        ],
                    ],
                ],
            ]
        )['blocks'];

        return $blocks;
    },
    1000,
    2
);

Cheers,
Chris :victory_hand:

1 Like

For the Social Sharing part:

Add this via the Code Snippets plugin

add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_style( 'font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css' );
} );

add_filter(
    'hivepress/v1/templates/listing_view_page/blocks',
    function( $blocks, $template ) {
        // Get the current post object
        global $post;
        
        // Check if we're on a HivePress listing page
        if ( $post && 'hp_listing' === $post->post_type ) {
            $permalink = get_permalink( $post->ID );
            $listing_title = get_the_title( $post->ID );
            
            // Ensure both permalink and title are not empty
            if ( ! empty( $permalink ) && ! empty( $listing_title ) ) {
                $blocks = hivepress()->helper->merge_trees(
                    [ 'blocks' => $blocks ],
                    [
                        'blocks' => [
                            'listing_actions_secondary' => [
                                'blocks' => [
                                    'custom_share_button' => [
                                        'type'    => 'content',
                                        'content' => '
                                            <style>
                                                .hp-share-modal {
                                                    display: none;
                                                    position: fixed;
                                                    top: 0;
                                                    left: 0;
                                                    width: 100%;
                                                    height: 100%;
                                                    background: rgba(0, 0, 0, 0.5);
                                                    z-index: 1000;
                                                    justify-content: center;
                                                    align-items: center;
                                                }
                                                .hp-share-modal__container {
                                                    background: #fff;
                                                    border-radius: 8px;
                                                    max-width: 400px;
                                                    width: 90%;
                                                    padding: 20px;
                                                    position: relative;
                                                    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
                                                }
                                                .hp-share-modal__close {
                                                    position: absolute;
                                                    top: 10px;
                                                    right: 15px;
                                                    background: none;
                                                    border: none;
                                                    font-size: 20px;
                                                    cursor: pointer;
                                                    color: #333;
                                                }
                                                .hp-share-modal__content h3 {
                                                    margin: 0 0 20px;
                                                    font-size: 1.2em;
                                                    color: #333;
                                                }
                                                .hp-share-options {
                                                    display: flex;
                                                    flex-direction: column;
                                                    gap: 12px;
                                                }
                                                .hp-share-options a {
                                                    display: flex;
                                                    align-items: center;
                                                    padding: 10px;
                                                    background: #f5f5f5;
                                                    border-radius: 4px;
                                                    text-decoration: none;
                                                    color: #333;
                                                    font-size: 0.9em;
                                                    transition: background 0.2s;
                                                }
                                                .hp-share-options a:hover {
                                                    background: #e0e0e0;
                                                }
                                                .hp-share-options i {
                                                    margin-right: 10px;
                                                    font-size: 1.2em;
                                                }
                                                .hp-listing__action--share {
                                                    cursor: pointer;
                                                }
                                            </style>
                                            <script>
                                                (function() {
                                                    console.log("Share script initialized");
                                                    var shareUrl = ' . json_encode( $permalink ) . ';
                                                    var shareTitle = ' . json_encode( $listing_title ) . ';
                                                    console.log("shareUrl set to:", shareUrl);
                                                    console.log("shareTitle set to:", shareTitle);

                                                    function isMobile() {
                                                        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
                                                    }

                                                    window.handleShare = function(event) {
                                                        event.preventDefault();
                                                        console.log("handleShare called, URL:", shareUrl);
                                                        try {
                                                            if (isMobile() && navigator.share) {
                                                                navigator.share({
                                                                    title: shareTitle,
                                                                    text: shareTitle,
                                                                    url: shareUrl
                                                                }).catch(function(error) {
                                                                    console.error("Native share failed:", error);
                                                                    showShareModal();
                                                                });
                                                            } else {
                                                                showShareModal();
                                                            }
                                                        } catch (error) {
                                                            console.error("Share error:", error);
                                                            showShareModal();
                                                        }
                                                    };

                                                    function showShareModal() {
                                                        var modal = document.getElementById("hp-share-modal");
                                                        if (modal) {
                                                            modal.style.display = "flex";
                                                            console.log("Modal shown");
                                                        } else {
                                                            console.error("Modal not found");
                                                        }
                                                    }

                                                    window.hideShareModal = function() {
                                                        var modal = document.getElementById("hp-share-modal");
                                                        if (modal) {
                                                            modal.style.display = "none";
                                                            console.log("Modal hidden");
                                                        }
                                                    };

                                                    window.shareFacebook = function(event) {
                                                        event.preventDefault();
                                                        var url = "https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(shareUrl);
                                                        console.log("Facebook share URL:", url);
                                                        openShareWindow(url);
                                                    };

                                                    window.shareWhatsApp = function(event) {
                                                        event.preventDefault();
                                                        var url = "https://api.whatsapp.com/send?text=" + encodeURIComponent(shareTitle + " " + shareUrl);
                                                        console.log("WhatsApp share URL:", url);
                                                        openShareWindow(url);
                                                    };

                                                    window.copyLink = function(event) {
                                                        event.preventDefault();
                                                        console.log("Copying URL:", shareUrl);
                                                        if (navigator.clipboard) {
                                                            navigator.clipboard.writeText(shareUrl).then(function() {
                                                                alert("Link copied to clipboard!");
                                                                console.log("Copy successful");
                                                            }).catch(function(error) {
                                                                console.error("Clipboard API failed:", error);
                                                                fallbackCopyLink(shareUrl);
                                                            });
                                                        } else {
                                                            console.log("Clipboard API not available, using fallback");
                                                            fallbackCopyLink(shareUrl);
                                                        }
                                                    };

                                                    function fallbackCopyLink(url) {
                                                        try {
                                                            var tempInput = document.createElement("input");
                                                            tempInput.style.position = "absolute";
                                                            tempInput.style.left = "-1000px";
                                                            tempInput.value = url;
                                                            document.body.appendChild(tempInput);
                                                            tempInput.select();
                                                            document.execCommand("copy");
                                                            document.body.removeChild(tempInput);
                                                            alert("Link copied to clipboard!");
                                                            console.log("Fallback copy successful");
                                                        } catch (error) {
                                                            console.error("Fallback copy failed:", error);
                                                            alert("Failed to copy link. Please copy the URL manually.");
                                                        }
                                                    }

                                                    function openShareWindow(url) {
                                                        try {
                                                            var win = window.open(url, "_blank", "width=600,height=400");
                                                            if (!win) {
                                                                console.error("Failed to open share window. Check pop-up blocker.");
                                                                alert("Unable to open share window. Please check your pop-up blocker.");
                                                            }
                                                        } catch (error) {
                                                            console.error("Error opening share window:", error);
                                                            alert("An error occurred while trying to share.");
                                                        }
                                                    }
                                                })();
                                            </script>
                                            <a class="hp-listing__action hp-listing__action--share hp-link" href="#" onclick="handleShare(event)">
                                                <i class="hp-icon fas fa-share-alt"></i>
                                                <span>Share</span>
                                            </a>
                                            <div id="hp-share-modal" class="hp-share-modal">
                                                <div class="hp-share-modal__overlay" onclick="window.hideShareModal()"></div>
                                                <div class="hp-share-modal__container">
                                                    <button class="hp-share-modal__close" onclick="window.hideShareModal()">×</button>
                                                    <div class="hp-share-modal__content">
                                                        <h3>Share this Listing</h3>
                                                        <div class="hp-share-options">
                                                            <a href="#" onclick="shareFacebook(event)">
                                                                <i class="fab fa-facebook-f"></i> Share on Facebook
                                                            </a>
                                                            <a href="#" onclick="shareWhatsApp(event)">
                                                                <i class="fab fa-whatsapp"></i> Share on WhatsApp
                                                            </a>
                                                            <a href="#" onclick="copyLink(event)">
                                                                <i class="fas fa-link"></i> Copy Link
                                                            </a>
                                                        </div>
                                                    </div>
                                                </div>
                                            </div>
                                        ',
                                        '_order' => 10,
                                    ],
                                ],
                            ],
                        ],
                    ]
                )['blocks'];
            }
        }
        return $blocks;
    },
    1000,
    2
);

Cheers,
Chris :victory_hand:

Hi,

Thanks for your suggestion, we’ll consider adding this feature.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.