Add agent listing page with ordering and disabled agent support

- Added agent_order (number) and agent_disabled (toggle) ACF fields
- Created archive-agent.php template for /agents/ listing page
  - Queries only active agents, ordered by agent_order then title
  - Grid layout with agent cards showing photo, name, title, bio
  - Contact action buttons (phone, email, profile)
- Added "Agents" link to footer fallback menu
- Updated single-agent.php to return 404 for disabled agents
- Updated property-agent.php to handle disabled agents:
  - Shows agent name and photo (for historical reference)
  - Replaces agent contact with office phone number
  - Removes Agent Profile button and email
  - Adds "Contact Us" button linking to contact form
- Added archive-agent.scss with responsive grid styles

Admin can now:
- Set display order for agents (lower numbers first)
- Disable agents who have left (hides from listing, 404s profile)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hanson.xyz Dev
2025-11-30 19:10:38 -06:00
parent 220ae51df8
commit 42a06a5435
8 changed files with 399 additions and 17 deletions
@@ -0,0 +1,148 @@
<?php
/**
* Archive Agent Template - Agent Listing Page
*
* @package HomeProz
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
get_header();
// Query active agents, ordered by agent_order then title
$agents_query = new WP_Query([
'post_type' => 'agent',
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => [
'relation' => 'OR',
// Agent is not disabled
[
'key' => 'agent_disabled',
'value' => '1',
'compare' => '!=',
],
// Or agent_disabled field doesn't exist yet
[
'key' => 'agent_disabled',
'compare' => 'NOT EXISTS',
],
],
'meta_key' => 'agent_order',
'orderby' => [
'meta_value_num' => 'ASC',
'title' => 'ASC',
],
]);
?>
<main id="primary" class="site-main Agents_Archive">
<?php
// Hero Section
get_template_part('template-parts/components/hero-section', null, array(
'title' => 'Our Team',
'subtitle' => 'Meet the dedicated professionals ready to help you find your perfect property.',
'size' => 'small',
));
?>
<section class="agents-section">
<div class="container">
<?php if ($agents_query->have_posts()) : ?>
<div class="agents-grid">
<?php while ($agents_query->have_posts()) : $agents_query->the_post();
$agent_id = get_the_ID();
$agent_phone = get_field('agent_phone', $agent_id);
$agent_email = get_field('agent_email', $agent_id);
$agent_title = get_field('agent_title', $agent_id);
$agent_short_bio = get_field('agent_short_bio', $agent_id);
// Get featured image
$agent_photo_id = get_post_thumbnail_id($agent_id);
$agent_photo_url = $agent_photo_id ? wp_get_attachment_image_url($agent_photo_id, 'medium_large') : '';
?>
<article class="agent-card-item">
<a href="<?php the_permalink(); ?>" class="agent-card-link">
<div class="agent-card-image">
<?php if ($agent_photo_url) : ?>
<img src="<?php echo esc_url($agent_photo_url); ?>" alt="<?php echo esc_attr(get_the_title()); ?>">
<?php else : ?>
<div class="agent-card-placeholder">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</svg>
</div>
<?php endif; ?>
</div>
<div class="agent-card-content">
<?php if ($agent_title) : ?>
<p class="agent-card-title-label"><?php echo esc_html($agent_title); ?></p>
<?php endif; ?>
<h2 class="agent-card-name"><?php the_title(); ?></h2>
<?php if ($agent_short_bio) : ?>
<p class="agent-card-bio"><?php echo esc_html($agent_short_bio); ?></p>
<?php endif; ?>
</div>
</a>
<div class="agent-card-actions">
<?php if ($agent_phone) : ?>
<a href="tel:<?php echo esc_attr(preg_replace('/[^0-9]/', '', $agent_phone)); ?>" class="agent-action-btn">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/>
</svg>
<span class="sr-only">Call</span>
</a>
<?php endif; ?>
<?php if ($agent_email) : ?>
<a href="mailto:<?php echo esc_attr($agent_email); ?>" class="agent-action-btn">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
<polyline points="22,6 12,13 2,6"/>
</svg>
<span class="sr-only">Email</span>
</a>
<?php endif; ?>
<a href="<?php the_permalink(); ?>" class="agent-action-btn agent-action-profile">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</svg>
<span>View Profile</span>
</a>
</div>
</article>
<?php endwhile; ?>
</div>
<?php else : ?>
<div class="no-agents-message">
<p>No team members to display at this time.</p>
</div>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
</div>
</section>
<?php
// CTA Section
get_template_part('template-parts/components/cta-section', null, array(
'title' => 'Ready to Get Started?',
'text' => 'Contact our team today to discuss your real estate needs.',
'button_text' => 'Contact Us',
'button_url' => home_url('/contact/'),
));
?>
</main>
<?php
get_footer();
File diff suppressed because one or more lines are too long
@@ -524,6 +524,36 @@ function homeproz_register_acf_fields() {
),
),
),
// Settings Tab
array(
'key' => 'field_agent_tab_settings',
'label' => 'Settings',
'name' => '',
'type' => 'tab',
'placement' => 'top',
),
array(
'key' => 'field_agent_order',
'label' => 'Display Order',
'name' => 'agent_order',
'type' => 'number',
'instructions' => 'Lower numbers appear first on the Agents page. Agents with the same order are sorted alphabetically.',
'default_value' => 10,
'min' => 0,
'max' => 999,
),
array(
'key' => 'field_agent_disabled',
'label' => 'Disable Agent',
'name' => 'agent_disabled',
'type' => 'true_false',
'instructions' => 'Disabled agents do not appear on the Agents page, their profile returns 404, and their contact info is hidden on property listings (replaced with office contact).',
'default_value' => 0,
'ui' => 1,
'ui_on_text' => 'Disabled',
'ui_off_text' => 'Active',
),
),
'location' => array(
array(
@@ -151,6 +151,7 @@ function homeproz_footer_fallback_menu() {
echo '<ul class="footer-menu">';
echo '<li class="menu-item"><a href="' . esc_url(home_url('/')) . '">Home</a></li>';
echo '<li class="menu-item"><a href="' . esc_url(home_url('/properties/')) . '">Properties</a></li>';
echo '<li class="menu-item"><a href="' . esc_url(get_post_type_archive_link('agent')) . '">Agents</a></li>';
echo '<li class="menu-item"><a href="' . esc_url(home_url('/about/')) . '">About</a></li>';
echo '<li class="menu-item"><a href="' . esc_url(home_url('/blog/')) . '">Blog</a></li>';
echo '<li class="menu-item"><a href="' . esc_url(home_url('/contact/')) . '">Contact</a></li>';
@@ -10,6 +10,20 @@ if (!defined('ABSPATH')) {
exit;
}
// Check if agent is disabled - return 404
if (have_posts()) {
the_post();
$agent_disabled = get_field('agent_disabled', get_the_ID());
if ($agent_disabled) {
global $wp_query;
$wp_query->set_404();
status_header(404);
get_template_part('404');
exit;
}
rewind_posts();
}
get_header();
while (have_posts()) :
+1
View File
@@ -27,6 +27,7 @@
@import '../template-parts/property/property-gallery.scss';
@import '../template-parts/property/single-property.scss';
@import '../template-parts/agent/single-agent.scss';
@import '../template-parts/agent/archive-agent.scss';
// Import reusable components
@import '../template-parts/components/hero-section.scss';
@@ -0,0 +1,156 @@
/**
* Agent Archive Styles
*
* @package HomeProz
*/
.Agents_Archive {
.agents-section {
padding: 3rem 0 4rem;
}
// Agents Grid
.agents-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
@media (min-width: 640px) {
grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 1024px) {
grid-template-columns: repeat(3, 1fr);
}
@media (min-width: 1280px) {
grid-template-columns: repeat(4, 1fr);
}
}
// Agent Card
.agent-card-item {
background-color: var(--color-bg-card);
border-radius: 0.5rem;
overflow: hidden;
display: flex;
flex-direction: column;
}
.agent-card-link {
display: block;
text-decoration: none;
color: inherit;
flex: 1;
&:hover {
.agent-card-image img {
transform: scale(1.05);
}
.agent-card-name {
color: var(--color-accent-light);
}
}
}
.agent-card-image {
aspect-ratio: 1 / 1;
overflow: hidden;
background-color: var(--color-bg-dark);
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
}
.agent-card-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: var(--color-text-muted);
}
.agent-card-content {
padding: 1.25rem;
}
.agent-card-title-label {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--color-accent);
margin-bottom: 0.375rem;
font-weight: 600;
}
.agent-card-name {
font-size: 1.25rem;
font-family: var(--font-display);
margin-bottom: 0.5rem;
line-height: 1.2;
}
.agent-card-bio {
font-size: 0.875rem;
color: var(--color-text-muted);
line-height: 1.5;
margin-bottom: 0;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
// Agent Card Actions
.agent-card-actions {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0 1.25rem 1.25rem;
margin-top: auto;
}
.agent-action-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
width: 40px;
height: 40px;
background-color: var(--color-bg-dark);
border-radius: 0.25rem;
color: var(--color-text-muted);
text-decoration: none;
&:hover {
background-color: var(--color-accent);
color: white;
}
&.agent-action-profile {
flex: 1;
width: auto;
font-size: 0.8125rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
}
// No Agents Message
.no-agents-message {
text-align: center;
padding: 3rem;
color: var(--color-text-muted);
p {
margin-bottom: 0;
}
}
}
@@ -3,6 +3,7 @@
* Property Agent Card Template Part
*
* Displays either the assigned agent (from Agent CPT) or a generic contact card
* Disabled agents show name/photo but use office contact info
*
* @package HomeProz
*/
@@ -19,12 +20,13 @@ $property_title = get_the_title($property_id);
// Build contact page URL with property parameter
$contact_url = add_query_arg('property', urlencode($property_title), home_url('/contact/'));
// Get company contact info as fallback
// Get company contact info
$company_phone = homeproz_get_option('phone');
$company_email = homeproz_get_option('email');
// Check if we have a valid agent from Agent CPT
$has_agent = false;
$agent_disabled = false;
$agent_name = '';
$agent_phone = '';
$agent_email = '';
@@ -33,9 +35,8 @@ $agent_photo_url = '';
if ($agent_id && get_post_type($agent_id) === 'agent') {
$has_agent = true;
$agent_disabled = get_field('agent_disabled', $agent_id);
$agent_name = get_the_title($agent_id);
$agent_phone = get_field('agent_phone', $agent_id);
$agent_email = get_field('agent_email', $agent_id);
$agent_title = get_field('agent_title', $agent_id);
// Get agent featured image
@@ -43,16 +44,32 @@ if ($agent_id && get_post_type($agent_id) === 'agent') {
if ($agent_photo_id) {
$agent_photo_url = wp_get_attachment_image_url($agent_photo_id, 'thumbnail');
}
// Only get agent contact info if NOT disabled
if (!$agent_disabled) {
$agent_phone = get_field('agent_phone', $agent_id);
$agent_email = get_field('agent_email', $agent_id);
}
}
?>
<?php if ($has_agent) : ?>
<?php $agent_profile_url = get_permalink($agent_id); ?>
<?php
// Agent profile URL - only link if not disabled
$agent_profile_url = !$agent_disabled ? get_permalink($agent_id) : null;
// Use company phone/email for disabled agents
$display_phone = $agent_disabled ? $company_phone : $agent_phone;
?>
<!-- Agent Card -->
<div class="sidebar-widget agent-card">
<div class="sidebar-widget agent-card<?php echo $agent_disabled ? ' agent-disabled' : ''; ?>">
<h3 class="widget-title">Listing Agent</h3>
<?php if ($agent_profile_url) : ?>
<a href="<?php echo esc_url($agent_profile_url); ?>" class="agent-info-link">
<?php else : ?>
<div class="agent-info-block">
<?php endif; ?>
<div class="agent-info">
<div class="agent-avatar">
<?php if ($agent_photo_url) : ?>
@@ -71,27 +88,33 @@ if ($agent_id && get_post_type($agent_id) === 'agent') {
<p class="agent-role"><?php echo esc_html($agent_title ?: 'Real Estate Agent'); ?></p>
</div>
</div>
<?php if ($agent_profile_url) : ?>
</a>
<?php else : ?>
</div>
<?php endif; ?>
<div class="agent-contact">
<?php if ($agent_phone) : ?>
<a href="tel:<?php echo esc_attr(preg_replace('/[^0-9]/', '', $agent_phone)); ?>" class="btn btn-primary">
<?php if ($display_phone) : ?>
<a href="tel:<?php echo esc_attr(preg_replace('/[^0-9]/', '', $display_phone)); ?>" class="btn btn-primary">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/>
</svg>
<?php echo esc_html($agent_phone); ?>
<?php echo esc_html($display_phone); ?>
</a>
<?php endif; ?>
<a href="<?php echo esc_url($agent_profile_url); ?>" class="btn btn-secondary">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</svg>
Agent Profile
</a>
<?php if ($agent_profile_url) : ?>
<a href="<?php echo esc_url($agent_profile_url); ?>" class="btn btn-secondary">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</svg>
Agent Profile
</a>
<?php endif; ?>
<?php if ($agent_email) : ?>
<?php if (!$agent_disabled && $agent_email) : ?>
<a href="mailto:<?php echo esc_attr($agent_email); ?>?subject=<?php echo esc_attr('Inquiry about ' . $property_title); ?>" class="btn btn-secondary">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
@@ -100,6 +123,15 @@ if ($agent_id && get_post_type($agent_id) === 'agent') {
Email Agent
</a>
<?php endif; ?>
<?php if ($agent_disabled) : ?>
<a href="<?php echo esc_url($contact_url); ?>" class="btn btn-secondary">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
Contact Us
</a>
<?php endif; ?>
</div>
</div>