Home / News / How to Build a Powerful WordPress Directory with Custom Fields and Advanced Search

How to Build a Powerful WordPress Directory with Custom Fields and Advanced Search

Here’s the sarcastic summary with hashtags:

WordPress is not just for blogging. With the right combination of plugins and custom code, you can turn it into a powerful platform for almost any kind of data-driven website, including a searchable directory.

For a recent project, universal-languages.fr, we needed to build a comprehensive directory of language schools, allowing users to search by location and keywords. In this tutorial, I’ll walk you through the exact process of how to build a similar directory from the ground up.

The Tech Stack

We’ll use a combination of powerful and flexible plugins to achieve our goal with minimal hassle:

  • Custom Post Type UI (CPT UI): To create a dedicated “Language School” post type, separating our listings from standard blog posts.
  • Advanced Custom Fields (ACF): To add custom data fields to our directory items (e.g., address, website, phone number).
  • WordPress is not just for blogging. With the right combination of plugins and custom code, you can turn it into a powerful platform for almost any kind of data-driven website, including a searchable directory.

    For a recent project, universal-languages.fr, we needed to build a comprehensive directory of language schools, allowing users to search by location and keywords. In this tutorial, I’ll walk you through the exact process of how to build a similar directory from the ground up.

    The Tech Stack

    We’ll use a combination of powerful and flexible plugins to achieve our goal with minimal hassle.

    1. Custom Post Type UI (CPT UI): To create a dedicated “Language School” post type, separating our listings from standard blog posts.
    2. Advanced Custom Fields (ACF): To add custom data fields to our directory items (e.g., address, website, phone number).
    3. WP Ultimate CSV Importer: To bulk-import data into our directory, saving hours of manual entry.
    4. Relevanssi: To supercharge the default WordPress search, making it faster and capable of searching through our custom fields.

    Step 1: Create the Custom Post Type

    First, we need a place to store our directory listings. Installing CPT UI allows us to do this without writing any register_post_type code.

    1. Install and activate the CPT UI plugin.
    2. Navigate to CPT UI > Add/Edit Post Types.
    3. Create a new post type. We’ll call it “Language School”. For the slug, our real-world project uses centre-formation (French for “training center”).
    4. Fill in the labels as needed (Plural, Singular, etc.).
    5. Under “Supports”, make sure Title, Editor, and Custom Fields are checked.
    6. Save the post type.

    You now have a new “Language Schools” menu in your WordPress admin!

    We also need a way to categorize our schools, for example, by city. For this, we use a custom taxonomy.

    1. Go to CPT UI > Add/Edit Taxonomies.
    2. Create a new taxonomy called “City” (ville).
    3. Attach it to our “Language School” post type.
    4. Save the taxonomy.

    Step 2: Define Custom Fields with ACF

    A directory listing is more than just a title and description. We need fields for structured data. This is where ACF shines.

    1. Install and activate Advanced Custom Fields.
    2. Go to Custom Fields > Add New.
    3. Create a Field Group named “School Details”.
    4. Set the rule to show this field group if Post Type is equal to Language School.
    5. Add your fields. For a school directory, you might add:
      • address (Text)
      • phone_number (Text)
      • website_url (Url)
      • email_address (Email)

    Now, when you edit a “Language School” post, you’ll see these fields ready for input.

    Step 3: Displaying a Single Directory Item

    To display a single listing, WordPress looks for a template file named single-{post_type_slug}.php. In our case, this is single-centre-formation.php.

    Create this file in your child theme’s folder and add the following code. It’s a standard WordPress loop, but we use ACF’s get_field() function to display our custom data.

    <?php get_header(); ?>
    
    <div id="primary" class="content-area">
        <main id="main" class="site-main">
    
        <?php
        while ( have_posts() ) :
            the_post();
            ?>
    
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <header class="entry-header">
                    <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
                </header>
    
                <div class="entry-content">
                    <h3>Details</h3>
                    <p><strong>Address:</strong> <?php echo esc_html( get_field('address') ); ?></p>
                    <p><strong>Phone:</strong> <?php echo esc_html( get_field('phone_number') ); ?></p>
                    <p><strong>Website:</strong> <a href="<?php echo esc_url( get_field('website_url') ); ?>" target="_blank">Visit Website</a></p>
    
                    <hr>
    
                    <?php the_content(); // This displays the main description from the WordPress editor ?>
                </div>
            </article>
    
        <?php endwhile; // End of the loop. ?>
    
        </main><!-- #main -->
    </div><!-- #primary -->
    
    <?php get_footer(); ?>
    

    Step 4: Building the Search Page and Logic

    This is the core of our directory. We’ll create a custom page template for the search form and a shortcode to process the search and display results.

    1. The Search Page Template (search_centres_page.php)

    Create a file named search_centres_page.php in your child theme with the following content. This template will hold our search form.

    <?php
    /*
    Template Name: School Search Page
    */
    get_header();
    ?>
    
    <div class="container">
        <h1>Find a Language School</h1>
    
        <form role="search" method="get" class="search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
            <input type="hidden" name="post_type" value="centre-formation" />
    
            <label>
                <span class="screen-reader-text">Search for:</span>
                <input type="search" class="search-field" placeholder="Search by keyword..." value="<?php echo get_search_query(); ?>" name="s" />
            </label>
    
            <?php
            // Dropdown for our "City" taxonomy
            wp_dropdown_categories( array(
                'taxonomy'         => 'ville',
                'name'             => 'ville',
                'show_option_all'  => 'All Cities',
                'value_field'      => 'slug',
                'hierarchical'     => true,
                'selected'         => get_query_var('ville'),
            ) );
            ?>
    
            <input type="submit" class="search-submit" value="Search" />
        </form>
    
        <div class="search-results">
            <?php echo do_shortcode('[centre_search_results]'); ?>
        </div>
    </div>
    
    <?php get_footer(); ?>
    

    Now, create a new page in WordPress and assign it the “School Search Page” template.

    2. The Shortcode for Displaying Results

    Add the following code to your child theme’s functions.php file. This code creates a shortcode [centre_search_results] that runs a WP_Query based on the URL parameters from our form.

    function centre_search_results_shortcode() {
        $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
        $search_query = get_search_query();
        $city_filter = isset($_GET['ville']) ? sanitize_text_field($_GET['ville']) : '';
    
        $args = array(
            'post_type'      => 'centre-formation',
            'posts_per_page' => 10,
            'paged'          => $paged,
            's'              => $search_query,
        );
    
        // If a city is selected, add a taxonomy query
        if ( !empty($city_filter) ) {
            $args['tax_query'] = array(
                array(
                    'taxonomy' => 'ville',
                    'field'    => 'slug',
                    'terms'    => $city_filter,
                ),
            );
        }
    
        $query = new WP_Query( $args );
    
        ob_start();
    
        if ( $query->have_posts() ) {
            echo '<div class="directory-listings">';
            while ( $query->have_posts() ) {
                $query->the_post();
                // Simple result display
                echo '<div class="listing-item">';
                echo '<h2><a href="' . get_permalink() . '">' . get_the_title() . '</a></h2>';
                echo '<p>' . esc_html(get_field('address')) . '</p>';
                echo '</div>';
            }
            echo '</div>';
    
            // Pagination
            echo paginate_links(array(
                'total' => $query->max_num_pages
            ));
    
        } else {
            echo '<p>No schools found matching your criteria.</p>';
        }
    
        wp_reset_postdata();
    
        return ob_get_clean();
    }
    add_shortcode( 'centre_search_results', 'centre_search_results_shortcode' );
    

    Why Relevanssi?
    By default, WordPress search is limited. By installing and activating Relevanssi, it automatically replaces the standard search. Configure it to index your centre-formation post type and its custom fields. Now, when a user types a keyword, Relevanssi will look inside the address, description, and other ACF fields, providing much more accurate results.

    Step 5: Bulk Import Your Data

    Manually adding hundreds of listings is not practical. This is where WP Ultimate CSV Importer comes in.

    1. Prepare a CSV file where the column headers match your ACF field names (e.g., address, phone_number).
    2. In the WordPress admin, go to the importer plugin’s page.
    3. Upload your file and map the CSV columns to the corresponding WordPress fields (post title, content, and your custom fields).
    4. Run the importer.

    Conclusion

    And there you have it! By combining the power of CPT UI, ACF, and Relevanssi, you can create a robust, searchable directory that is both easy to manage and powerful for the end-user. The final step is to add your own CSS to style.css to make it look great. This modular approach is highly flexible and serves as a fantastic foundation for even more complex directory projects.

Tagged:

Leave a Reply

Your email address will not be published. Required fields are marked *