How to Generate Shareable Preview Links for Draft Posts, Pages, and CPTs in WordPress without any plugins

When working on a WordPress website—whether you’re a developer, content creator, or agency—it’s common to share draft pages or posts with clients before publishing.

However, by default, WordPress requires users to be logged in to view draft content. This can be inconvenient when you simply want to share a preview link with a client or team member who doesn’t have WordPress access.

Most people install plugins to do this, but you can generate secure, shareable preview links without any plugin using a small custom code snippet.

In this guide, you’ll learn how to:

  • Allow non-logged-in users to view draft previews
  • Generate a shareable URL for any post type
  • Automatically display a “Sharable Link” meta box in the WordPress editor
  • Add one-click buttons to copy or open the preview link
  • Support posts, pages, and unlimited custom post types (CPTs)

Why Do You Need Shareable Draft Links?

Here are common scenarios where this is extremely useful:

  • Sending preview links to clients
  • Allowing team members to review draft content
  • Sharing landing pages or funnels under development
  • Getting approval on blog posts, pages, or custom post types
  • Avoiding unnecessary WordPress accounts or login steps

How the Solution Works

We will:

  • Add a URL parameter key=guest
  • Modify the main query to allow draft preview when this key is present
  • Add a meta box that generates the shareable link
  • Automatically show the live URL for published posts
  • Allow preview URL for draft/unpublished posts
  • Add “Copy Link” and “Open Link” buttons

Full Code: Shareable Preview Link Generator

Place this code in your child theme’s functions.php File.

Code Snippet:

add_action('pre_get_posts', 'allow_draft_preview');
function allow_draft_preview($query) {
    if (isset($_GET['key']) && $_GET['key'] == 'guest') {
        if ($query->is_main_query()) {
            $query->set('post_status', array('publish', 'draft'));
        }
    }
}
add_action('add_meta_boxes', function () {
// Define your target post types
$custom_post_types = ['post', 'page', 'people', 'locations', 'practiceareas', 'alerts', 'blog', 'events', 'news', 'publications', 'video', 'open-positions'];
foreach ($custom_post_types as $post_type) {
        if (post_type_exists($post_type)) {
            add_meta_box(
                'sharable_link_box',
                'Sharable Link',
                'render_sharable_link_box',
                $post_type,
                'side',
                'high'
            );
       }
    }
}, 20); // Priority 20 ensures CPTs are registered

function render_sharable_link_box($post) {
    $is_published = $post->post_status === 'publish';
    if ( $is_published ) {
        $url = esc_url( get_permalink( $post->ID ) );
        $label = 'Live URL';
    } else {
        $preview_url = get_preview_post_link( $post->ID );
        $url = esc_url( add_query_arg( 'key', 'guest', $preview_url ) );
        $label = 'Preview URL';
    }
    echo '<label style="font-weight: bold; display: block; margin-bottom: 5px;">' . esc_html( $label ) . '</label>';
    echo '<input type="text" readonly value="' . $url . '" style="width:100%; font-size:12px;" id="sharableLinkURL">';
    echo '<div style="margin-top:8px; display:flex; gap:8px; flex-wrap:wrap;">';
    echo '<button type="button" class="button" onclick="copySharableURL()">Copy Link</button>';
    echo '<button type="button" class="button button-secondary" onclick="openSharableURL()">Open in New Tab</button>';
    echo '</div>';

// JS for buttons
echo <<<HTML
<script>
function copySharableURL() {
    const input = document.getElementById('sharableLinkURL');
    input.select();
    input.setSelectionRange(0, 99999); // For mobile
    document.execCommand('copy');
    alert('URL copied to clipboard!');
}
function openSharableURL() {
    const input = document.getElementById('sharableLinkURL');
    const url = input.value;
    window.open(url, '_blank');
}
</script>
HTML;
}

How to Use the Shareable Link

Once the code is active:

1. Edit any post, page, or CPT

You’ll see a new meta box on the right side labeled “Sharable Link”.

2. For published posts

It shows the Live URL.

3. For draft or pending posts

It shows a secure preview URL like:

https://yoursite.com/?p=123&preview=true&key=guest

4. Share it with your client

They do not need to log in.

5. Use the built-in buttons

  • Copy Link → copies URL to clipboard
  • Open in New Tab → loads preview instantly


Conclusion

With just a few lines of code, you can easily generate shareable preview links for any WordPress post type—without plugins.

If you’re building a WordPress site that requires custom workflows, advanced CMS logic, or plugin-free solutions, our team can take complete ownership of the project—from planning and development to testing and launch.

You can Book a Free Project Consultation to discuss your requirements, timelines, and how we can deliver the entire solution for you.

How to Bulk Update Image File Names and titles in WordPress Without Breaking Page Content for SEO purpose

How to Bulk Update Image File Names and titles in WordPress Without Breaking Page Content for SEO purpose

Images play a major role in SEO. When your image file names and titles are optimized correctly, search engines can better understand your content — helping you rank higher in Google Image Search and improving overall keyword relevance.

But updating image file names manually can be risky. One wrong step and your pages may break, leaving broken image links across your website.

The good news? You can bulk update image file names and titles safely in WordPress using a powerful tool: Phoenix Media Rename.

In this guide, you’ll learn:

  • Why optimized image names help SEO
  • How to rename images safely without breaking pages
  • How Phoenix Media Rename automatically updates all internal links
  • Best practices for SEO-friendly file names
  • Tips for bulk renaming efficiently

Step 1: Install Phoenix Media Rename

  • Go to Plugins → Add New
  • Search “Phoenix Media Rename”
  • Install & activate

Step 2: Bulk Rename Images (Individually or in Groups)

  • Go to Media → Library → List View
  • You will see a new rename field next to each image
  • Update the file name and title
  • Then select Rename & Retitle
  • Then click on apply for update

Add update image name

Benefits of Phoenix Media Rename for SEO

  • Boosts image search visibility
  • Fixes messy media libraries
  • Prevents broken URLs
  • Keeps all page layouts intact
  • Helps search engines understand your content better
  • Speeds up images optimization

Conclusion

Renaming image file names is one of the simplest yet most powerful SEO improvements you can make — but it must be done safely.
With Phoenix Media Rename, you can bulk rename image files and update titles across your entire WordPress site without breaking a single link.

If you’re serious about improving SEO, cleaning up your media names is a highly effective step.

If you’re managing a WordPress site with hundreds (or thousands) of images and need bulk SEO-friendly updates without risking content or rankings, our team can handle the entire process—from planning and execution to validation and rollout.

You can Schedule a Free Consultation to discuss your site structure, SEO concerns, and how we can safely implement large-scale WordPress changes for you.

How to Create a Custom Rich Text Editor in Gravity Forms for Better Formatting and User Experience

How to Create a Custom Rich Text Editor in Gravity Forms for Better Formatting and User Experience

Gravity Forms is one of the most powerful form builders available for WordPress — but it has one limitation:

It does not offer a built-in Rich Text Editor (WYSIWYG) field.

For websites that rely on user-generated content—such as blogs, directories, reviews, job listings, or frontend post submissions—a basic textarea simply isn’t enough.

A proper Rich Text Editor allows users to format text with:

  • Headings (H1–H6)
  • Links & Media
  • Bold, Italic, Underline
  • Bullet and Numbered Lists
  • Images
  • Blockquotes
  • Inline styles like alignment, colors, and spacing

So in this tutorial, you’ll learn how to add a fully functional Rich Text Editor field inside Gravity Forms using custom code — without installing an extra plugin.

What This Solution Supports

  • Works on frontend
  • Uses TinyMCE (WordPress default editor)
  • Supports media uploads
  • Outputs clean formatted HTML
  • Works with Gravity Forms Post Creation Add-On
  • Prevents raw HTML from showing in visual mode

Why You Need a Custom Rich Text Editor in Gravity Forms

A normal textarea field cannot store or render formatted content like:

  • Titles and headings
  • Styled paragraphs
  • Embedded media or images
  • Links and structured lists

If you’re building forms like:

  • Blog submission form
  • Directory or listing submission
  • User reviews
  • Job listing submission
  • Knowledgebase article submission
  • Community-generated content

…then users need a proper editor — not a plain text field.

Step-by-Step Guide

Step 1 — Add This Code to Your functions.php

Copy and paste the following entire code block into your theme’s functions.php or a custom plugin:

( Code already formatted, so no changes needed — paste exactly as provided.)

// Enable a fully functional Rich Text Editor field in Gravity Forms
// Works on frontend + shows formatted output (not HTML tags)

//Enqueue editor scripts (TinyMCE + Media)
add_action('gform_enqueue_scripts', function() {
    wp_enqueue_editor();
    wp_enqueue_media();
});

// 1. Add "Rich Text Editor" button to Form Builder

add_filter('gform_add_field_buttons', function($field_groups){
    $field_groups[] = array(
        'name'   => 'custom_fields',
        'label'  => __('Custom Fields', 'gravityforms'),
        'fields' => array(
            array(
                'class' => 'button',
                'value' => __('Rich Text Editor', 'gravityforms'),
                'data-type' => 'editor',
            ),
        ),
    );
    return $field_groups;
});

// 2. Register field type name

add_filter('gform_field_type_title', function($type){
    return $type === 'editor' ? __('Rich Text Editor', 'gravityforms') : $type;
});

// 3. Add standard settings (optional)
add_action('gform_field_standard_settings', function($position, $form_id){
    if($position == 25){ ?>
        <li class="field_setting">
            <label for="field_placeholder">
                <?php esc_html_e("Placeholder", "gravityforms"); ?>
                <?php gform_tooltip("form_field_placeholder"); ?>
            </label>
            <input type="text" id="field_placeholder" class="fieldwidth-3" size="35"
                onkeyup="SetFieldProperty('placeholder', this.value);" />
        </li>
    <?php }
}, 10, 2);

// 4. Editor JS for Gravity Form Builder
add_action('gform_editor_js', function(){ ?>
<script type='text/javascript'>
    fieldSettings.editor = '.label_setting, .description_setting, .css_class_setting, .placeholder_setting, .visibility_setting, .required_setting';
</script>
<?php });

// 5. Render the TinyMCE editor on frontend

add_filter('gform_field_input', function($input, $field, $value, $lead_id, $form_id){
    if($field->type !== 'editor') return $input;

    ob_start();
    wp_editor(
        $value,
        'input_' . $form_id . '_' . $field->id,
        array(
            'textarea_name' => 'input_' . $field->id,
            'media_buttons' => true,
            'quicktags'     => true,
            'tinymce'       => array(
                'height' => 300,
                'toolbar1' => 'formatselect bold italic underline | bullist numlist blockquote | alignleft aligncenter alignright link unlink | removeformat',
            ),
        )
    );
    $editor_html = ob_get_clean();

    return sprintf(
        '<div class="ginput_container ginput_container_editor">%s</div>',
        $editor_html
    );
}, 10, 5);

// Safe rendering decode and render formatted HTML (not tags)

if ( ! function_exists( 'gf_rich_allowed_tags' ) ) {
    function gf_rich_allowed_tags() {
        return array(
            'p'      => array(),
            'br'     => array(),
            'strong' => array(),
            'b'      => array(),
            'em'     => array(),
            'i'      => array(),
            'u'      => array(),
            'span'   => array( 'style' => true, 'class' => true ),
            'div'    => array( 'style' => true, 'class' => true ),
            'a'      => array( 'href' => true, 'title' => true, 'target' => true, 'rel' => true ),
            'h1'     => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(),
            'ul'     => array(), 'ol' => array(), 'li' => array(),
            'blockquote' => array(),
            'img'    => array( 'src' => true, 'alt' => true, 'width' => true, 'height' => true ),
            'strong' => array(), 'em' => array()
        );
    }
}

/* ---------- Allow safe inline CSS properties ---------- */
add_filter( 'safe_style_css', function( $styles ) {
    $custom = array(
        'text-decoration',
        'color',
        'background-color',
        'font-size',
        'font-weight',
        'font-style',
        'text-align',
        'line-height',
        'font-family',
    );
    return array_unique( array_merge( $styles, $custom ) );
});

/* ---------- Helper to decode + sanitize editor HTML ---------- */
if ( ! function_exists( 'gf_render_editor_html_safe' ) ) {
    function gf_render_editor_html_safe( $raw ) {
        if ( $raw === null || $raw === '' ) {
            return '';
        }

        // 1) Decode HTML entities (handles encoded "<" as &lt;)
        $decoded = html_entity_decode( (string) $raw, ENT_QUOTES | ENT_HTML5, 'UTF-8' );

        // 2) Fix possible double-encoding like &amp;lt;
        if ( strpos( $decoded, '&amp;lt;' ) !== false || strpos( $decoded, '&amp;gt;' ) !== false ) {
            $decoded = str_ireplace( array( '&amp;lt;', '&amp;gt;' ), array( '<', '>' ), $decoded );
            $decoded = html_entity_decode( $decoded, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
        }

        // 3) Sanitize with allowed tags (keeps <a href>, <span style>, etc.)
        return wp_kses( $decoded, gf_rich_allowed_tags() );
    }
}

/* ---------- Merge-tag replacement: decode + render editor fields (priority 5) ---------- */
add_filter( 'gform_replace_merge_tags', function( $text, $form, $entry, $url_encode, $esc_html, $nl2br ) {
    if ( empty( $form ) || empty( $entry ) ) {
        return $text;
    }

    // decode the container text early (handles already-encoded merge outputs)
    $text = html_entity_decode( (string) $text, ENT_QUOTES | ENT_HTML5, 'UTF-8' );

    foreach ( $form['fields'] as $field ) {
        if ( isset( $field->type ) && $field->type === 'editor' ) {
            $id  = $field->id;
            $raw = rgar( $entry, $id );

            // render the raw field value safely (allows links, styles)
            $rendered = gf_render_editor_html_safe( $raw );

            // Replace merge tags: {ID} and {Label:ID} and {Label:ID:modifier}
            $text = str_replace( '{' . $id . '}', $rendered, $text );

            $pattern = '/\{[^}]*:' . preg_quote( $id, '/' ) . '(?::[^}]*)?\}/';
            $text = preg_replace( $pattern, $rendered, $text );
        }
    }

    // Final pass: ensure we haven't left encoded common tags; decode conservative patterns
    if ( strpos( $text, '&lt;' ) !== false || strpos( $text, '&amp;lt;' ) !== false ) {
        $search = array(
            '&lt;br /&gt;','&lt;br&gt;','&lt;br/&gt;',
            '&lt;p&gt;','&lt;/p&gt;',
            '&lt;h1&gt;','&lt;/h1&gt;','&lt;h2&gt;','&lt;/h2&gt;','&lt;h3&gt;','&lt;/h3&gt;',
            '&lt;h4&gt;','&lt;/h4&gt;','&lt;h5&gt;','&lt;/h5&gt;','&lt;h6&gt;','&lt;/h6&gt;',
            '&lt;strong&gt;','&lt;/strong&gt;','&lt;b&gt;','&lt;/b&gt;',
            '&lt;em&gt;','&lt;/em&gt;','&lt;i&gt;','&lt;/i&gt;','&lt;u&gt;','&lt;/u&gt;',
            '&lt;span&gt;','&lt;/span&gt;','&lt;div&gt;','&lt;/div&gt;',
            '&lt;a href=&quot;','&lt;/a&gt;',
            '&amp;lt;','&amp;gt;'
        );
        $replace = array(
            '<br />','<br>','<br/>',
            '<p>','</p>',
            '<h1>','</h1>','<h2>','</h2>','<h3>','</h3>',
            '<h4>','</h4>','<h5>','</h5>','<h6>','</h6>',
            '<strong>','</strong>','<b>','</b>',
            '<em>','</em>','<i>','</i>','<u>','</u>',
            '<span>','</span>','<div>','</div>',
            '<a href="','</a>',
            '<', '>'
        );

        $text = str_ireplace( $search, $replace, $text );
    }

    // Finally sanitize entire result again with allowed tags (keeps a href + span style)
    $text = wp_kses( $text, gf_rich_allowed_tags() );

    return $text;
}, 5, 6 );


/**
 * 3) Ensure gform_get_input_value returns safe rendered HTML for editor fields.
 *    Many templates/plugins call this directly to get the field value.
 */
add_filter( 'gform_get_input_value', function( $value, $entry, $field, $input_id ) {
    if ( is_object( $field ) && isset( $field->type ) && $field->type === 'editor' ) {
        return gf_render_editor_html_safe( $value );
    }
    return $value;
}, 10, 4 );

/**
 * 4) Admin Entry Detail try to force rendered HTML on entry detail page
 */
add_filter( 'gform_entry_field_value', function( $value, $field, $entry ) {
    if ( is_object( $field ) && isset( $field->type ) && $field->type === 'editor' ) {
        return gf_render_editor_html_safe( $value );
    }
    return $value;
}, 10, 3 );

/**
 * 5) Shortcode: [gf_editor entry="123" field="2"]
 *    Use this in templates/content to safely print the rendered editor field.
 */
if ( ! shortcode_exists( 'gf_editor' ) ) {
    add_shortcode( 'gf_editor', function( $atts ) {
        $atts = shortcode_atts( array(
            'entry' => '',
            'field' => '',
        ), $atts, 'gf_editor' );

        $entry_id = intval( $atts['entry'] );
        $field_id = intval( $atts['field'] );

        if ( $entry_id <= 0 || $field_id <= 0 ) return '';

        $entry = GFAPI::get_entry( $entry_id );
        if ( is_wp_error( $entry ) ) return '';

        $raw = rgar( $entry, $field_id );
        return gf_render_editor_html_safe( $raw );
    } );
}

Once added, Gravity Forms will display a new field called:  Rich Text Editor under the “Custom Fields” tab.

 

Step 2 — Create a New Gravity Form

  1. Go to Forms → New Form
  2. Give it a name (Example: Blog Submission Form)
  3. Add standard fields like:
    • Name
    • Email
    • Post Title
  4. Add your new field: Rich Text Editor
  5. Save the form

Tip: Note the Field ID for later (Example: Field ID: 10).

Step 3 — Configure Gravity Forms Post Creation Add-On

  1. Go to Form → Settings → Post Creation
  2. Create a new feed
  3. Settings example:
Setting Example
Post Type Post (or Custom Post Type)
Status Draft (recommended for testing)
Author Logged-in User
Title {Post Title:1}
Content {Description:10} ← must match Rich Editor Field ID

(Optional) Map:

  • Categories
  • Tags
  • Featured Image
  • Custom fields

Important: Ensure the content field uses the field ID of the Rich Text Editor.

Step 4 — Add the Form to a Page

Use this shortcode anywhere:
[ gravityform id="123" title="true" description="false" ajax="true" ]

Replace 123 with your form ID.

Publish your page (example: Submit a Blog).

Step 5 — Test the Submission

  1. Open the form on the frontend
  2. Format content using the editor (bold, headings, images, lists, etc.)
  3. Submit the form
  4. Check:

Posts → All Posts

You should see a new post created — with formatting preserved.

  1. In WP Admin go to Posts → All Posts and find the new post (status based on your feed setting).
  2. Click Edit on the post and check the Visual tab in the editor — the content should render as formatted HTML (not raw HTML tags).
  3. View the post on the frontend and confirm headings, lists, images and styling display correctly.

Final Result

You now have a fully working frontend content editor inside Gravity Forms — without additional plugins.

  • Works with WordPress media uploader
  • Supports formatting, links, images, headings
  • Perfect for guest posting, user-generated content, and custom submission workflows

Conclusion

Adding a rich text editor to Gravity Forms dramatically improves the user experience for forms involving long-form content.

Whether you’re building a submission portal, directory, review system, or frontend publishing workflow — this upgrade makes Gravity Forms behave more like a real blogging platform.

If your project requires custom Gravity Forms functionality, enhanced user experience, or plugin-free custom editors, our team can handle the complete development—from planning and implementation to testing and launch.

You can Book a Free Project Consultation to discuss your requirements, timelines, and how we can deliver a scalable, high-quality solution for your website.

How to Hide Divi Sections, Rows, and Columns Automatically When ACF Fields Are Empty

How to Hide Divi Sections, Rows, and Columns Automatically When ACF Fields Are Empty

When building dynamic templates using Divi + Advanced Custom Fields (ACF), you may want certain sections or columns to appear only if the ACF field has a value.
For example:

  • Show the “Contact Information” section only if the product has phone/email fields
  • Hide empty specifications
  • Hide columns that have no ACF content

Divi makes this very easy using Conditional Display Logic.

In this guide, I’ll show you how you can hide:

  • Individual blurbs
  • Columns
  • Entire sections

…based on whether ACF fields contain data.

Step 1: Edit Your Template in Divi Builder

Open your template in:

Divi → Theme Builder → Product Template (or any template)

Here I created a Product Template and added multiple ACF fields to each product.

Open your template in: Divi → Theme Builder → Product Template (or any template) Here I created a Product Template and added multiple ACF fields to each product.

Step 2: Add ACF Fields Inside Blurbs

Now add your ACF content inside multiple Blurb Modules.

I added the ACF field value inside the Body of each blurb.

  • Title = Your label (e.g., “Toll Free Number”)
  • Body = Select ACF Field from Dynamic Content

This allows each blurb to show the product data dynamically.

Add ACF Fields Inside Blurbs

Step 3: Apply Display Conditions on Each Column

Now, we want each column to appear only if its blurb has ACF data.

To do this:

  1. Open Column Settings
  2. Go to Advanced → Conditions
  3. Add condition:
    • Custom Field
    • Field Name → your ACF field key (example: toll_free_number)
    • Display Only If → Is Any Value

Apply Display Conditions on Each Column
This means:

  • If that ACF field has ANY data → the column appears
  • If the field is empty → the column hides automatically

Repeat this for all columns with ACF blurbs.

Repeat this for all columns with ACF blurbs

Step 4: Hide Entire Section When All ACF Fields Are Empty

Now we want the main section to hide if all inner fields are empty.

To do that:

  1. Open Section Settings
  2. Go to Advanced → Conditions
  3. Add multiple conditions for all ACF fields you used
  4. Use “OR” logic (default behavior)
  5. Condition:
    • Display only if Custom Field is any value

Hide Entire Section When All ACF Fields Are Empty

This means:

  • If any one ACF field has data → Section is visible
  • If all ACF fields are empty → Section hides automatically

Step 5: Save Template & Test

That’s it!

Now:

  • If any column has its ACF data → column shows
  • If ACF data is missing → column hides
  • If all ACF blurbs are empty → entire section hides
  • If at least one field has a value → section appears normally

This keeps your product or page templates clean, dynamic, and fully automated.

If your website relies on ACF-powered layouts, dynamic visibility logic, or custom Divi behavior, our team can handle the complete development—from planning and implementation to testing and launch—without plugin bloat.

You can Book a Free Project Consultation to discuss your requirements, timelines, and how we can deliver a scalable, production-ready solution for your site.

Create Dynamic Upcoming & Past Event Listings with JetEngine Query Builder

Create Dynamic Upcoming & Past Event Listings with JetEngine Query Builder

Displaying events in a clean “Upcoming” and “Past” format is one of the most requested features on WordPress event websites. Whether you’re managing workshops, webinars, conferences, or local meetups—showing events in the right chronological order boosts user engagement and improves navigation.

With JetEngine’s Query Builder, you can easily create two dynamic listings:

Upcoming Events – sorted by closest future date

Past Events – sorted by most recent past date

In this guide, you’ll learn how to build both listings from scratch using JetEngine, Elementor, and your custom event date fields.

Why Use JetEngine Query Builder for Event Filters?

JetEngine gives you powerful control over custom post types, meta fields, and dynamic content. With the Query Builder, you can:

– Filter events by date automatically

– Sort events by ascending/descending order

– Display upcoming & past events on any page

– Reuse the queries across multiple listings

– Avoid writing custom PHP code

Step 1: Prepare Your Event Structure

  1. Create a Custom Post Type
    – JetEngine → Post Types → Add “Events”
  2. Add an Event Date Meta Field
    – JetEngine → Meta Fields
    – Field Name: event_start_date
    – Field Name: event_end_date
    – Field Type: Date (or DateTime)
    – Save Format: Y-m-d

Step 2: Build the Query for Upcoming Events

  1. JetEngine → Query Builder → Add New
  2. Query Type: Posts Query
  3. Post Type: Events
  4. Sorting:
    – Order By: By date
    – Order: ASC ( From lowest to highest values (1, 2, 3; a, b, c) )
  5. Meta Query:
    – Key: event_end_date
    – Operator: Greater than ( > )
    – Value: Today
    – Type: Numeric
  6. Name it: Upcoming Events Query

Step 3: Build the Query for Past Events

  1. JetEngine → Query Builder → Add New
  2. Query Type: Posts Query
  3. Post Type: Events
  4. Sorting:
    – Order By: By date
    – Order: ASC ( From highest to lowest values (3, 2, 1; c, b, a) )
  5. Meta Query:
    – Key: event_end_date
    – Operator: Less than ( < )
    – Value: Today
    – Type: Numeric
  6. Name it: Past Events Query

Step 4: Create the Event Listing Template

  1. JetEngine → Listings → Add New
  2. Select CPT: Events
  3. Add:
    – Dynamic Title
    – Event Start Date
    – Event End Date
    – Featured Image
    – Location
    – View Details Button

Step 5: Add Upcoming & Past Listings on a Page

  • For Upcoming Events:
    – Add Listing Grid in Elementor
    – Enable Custom Query
    – Select: Upcoming Events Query
  • For Past Events:
    – Repeat with: Past Events Query

Final Thoughts

Using JetEngine’s Query Builder makes event management fast, scalable, and automatic. Your listings update dynamically without manual work, making your website more professional and user-friendly.

If you’re building a WordPress site with dynamic event listings, date-based queries, or complex JetEngine logic, our team can take full ownership of the project—from data structure and query setup to frontend integration and performance optimization.

You can Book a Free Project Consultation to discuss your goals, timelines, and how we can deliver a reliable, scalable solution tailored to your website.

How to Create a Professional Sticky Shrink Header in Divi Without Any Plugins

A clean, modern website isn’t just about colors and layout — it’s also about user experience. One of the most popular UX enhancements used on professional websites today is the sticky shrinking header.

This feature allows your navigation bar to stay visible as users scroll, while smoothly shrinking in size to maximize screen space. It keeps important navigation links always accessible and improves the browsing experience — especially on long pages.

In this tutorial, we’ll walk you through how to create a professional sticky shrink header in Divi using built-in features — fast, clean, and performance-friendly.

Why Use a Sticky Shrink Header?

A well-optimized header can make a big difference in how visitors interact with your site. Sticky headers provide:

  • Continuous navigation access
  • Better UX for mobile and desktop users
  • Modern, professional design feel
  • More space for content while keeping branding visible

Whether you’re building a business site, portfolio, or e-commerce store, this effect adds polish and functionality your visitors will notice.

Step-by-Step: Create a Sticky Shrink Header Using Divi

Below is the exact method we used to build this feature in our demo site — and you can follow the same steps:

Step 1: Create a New Header Layout

  1. Go to: Divi → Theme Builder
  2. Click Add Global Header or create a custom header for selected post types or pages.
  3. Choose Build From Scratch.

Step 2: Add Your Structure

Inside your header, add:

  • Section
  • Row
  • Menu Module

This will be the foundation for your navigation.

Step 3: Enable Sticky Behavior

Now the magic begins.

  1. Open the Menu Module Settings
  2. Go to: Advanced → Scroll Effects
  3. Under Sticky Position, select: Sticky: Top

Once enabled, Divi will display a new sticky icon next to editable fields (similar to hover states).

Step 4: Apply Shrinking Effects (Sticky State Styling)

To create a professional shrinking effect, adjust the following settings for both normal and sticky states:

  • Logo Size
  • Menu Text Size
  • Padding / Spacing
  • Background Color
  • Box Shadow (optional)

Example:

Property Normal State Sticky State
Logo Height 40px 30px
Menu Font Size 18px 16px
Top/Bottom Padding 30px 10px

These subtle visual changes create a smooth professional shrinking animation when users scroll.

Step 5: Save & Publish

Once everything looks perfect:

Click Save → Exit the Theme Builder → Visit your site.

You should now see your sticky shrink header in action — smooth, modern, and fully responsive.

Final Result: A Clean, Modern Navigation Experience

Your new header will now:

  • Stick to the top while scrolling
  • Shrink smoothly to save space
  • Maintain full navigation visibility
  • Enhance overall user experience

All without installing extra plugins or affecting site speed.

Final Thoughts

A sticky shrinking header may seem like a small design change, but it dramatically improves:

  • Branding visibility
  • Navigation usability
  • Professional perception

If you’re building a WordPress site that requires custom Divi UI interactions, sticky headers, or performance-optimized front-end behavior, our team can take full ownership of the project—from design implementation and development to testing and launch.

You can Schedule a Consultation to discuss your goals, timelines, and how we can deliver a polished, production-ready solution for your website.

How to Create a Custom Single Business Listing Template in Elementor for the Directory Plugin

If you’re using Directorist – Business Directory Plugin and want to customize your single listing page layout using Elementor without writing complex templates, you’re in the right place.
In this tutorial, you’ll learn how to structure your single business listing page into a two-column layout and control what content appears on the left or right—using a simple CSS class and small JavaScript snippet.

Step 1: Install the Directorist Plugin

First, install the plugin from the official WordPress repository:

Directorist – Business Directory Plugin (Available in WordPress Plugins Directory)

you can direct download and install from official worpress : https://wordpress.org/plugins/directorist/

You can install it here:
Go to Plugins → Add New → Search “Directorist” → Install → Activate

Step 2: Open the Directory Builder

Once installed, go to:

Dashboard → Directory Listings → Directory Builder → Single Page Layout

This is where you will customize the single listing design.

Configure the Listing Header

Click on Listing Header and toggle ON/OFF the elements you want to display:

  • Back Button
  • Bookmark
  • Share
  • Report
  • Listing Title
  • Location
  • Category
  • Rating
  • Badges
  • Pricing

Configure Your Listing Contents

Next, go to:

Listing Contents

Drag, reorder, or remove blocks like:

  • Description
  • Business Information
  • Business Photos
  • Location Map
  • Reviews
  • Related Listings
  • Author Info
  • Custom Content

After you finish arranging fields, click Update.

Step 3: Assign Left or Right Column Placement

Now we need to tell the system which content belongs in the sidebar and which belongs in the main content area.

Click a section → open its settings → find Custom Block Classes.

Add one of the following:

Class Name Layout Position
left-side Appears in left/main content section
right-side Appears inside the sidebar

Example:

  • Description → left-side
  • Business Info / Contact Form → right-side

Step 4: Add Custom Elementor JavaScript

Now we’ll use a small script to organize the layout structure.

Go to:

Elementor → Custom Code → Add New

  • Name: Create Directory Single Page JS
  • Location: Header or Footer (recommended Footer)

Paste this script:

<script>
jQuery(document).ready(function($) {

  // Insert new layout row after the listing header
  $('.directorist-single .directorist-single-wrapper .directorist-single-listing-header').after(`
    <div class="directorist-row directorist-single-bottom">
      <div class="directorist-single-bottom-left directorist-col-lg-8"></div>
      <div class="directorist-single-bottom-right directorist-col-lg-4"></div>
    </div>
  `);

  // Move left-side items into left content area
  $('.directorist-single .directorist-single-wrapper > .left-side')
    .appendTo('.directorist-single .directorist-single-wrapper .directorist-single-bottom-left');
  // Move right-side items into sidebar
  $('.directorist-single .directorist-single-wrapper > .right-side')
    .appendTo('.directorist-single .directorist-single-wrapper .directorist-single-bottom-right');
});
</script>

Save and make sure it applies sitewide or only on Directorist single pages (recommended).

Step 5: Style and Customize

Now that the structure is created, you can:

  • Add spacing
  • Add backgrounds
  • Customize typography
  • Style widgets

Make it visually match your directory branding.

Final Output

You’ll now have a clean, structured two-column layout where:

  • Main business details appear on the left
  • Contact, map, info, and widgets appear on the right sidebar

Conclusion

With just a few simple steps and a small JavaScript tweak, you can fully customize the Directorist Single Listing Page layout using Elementor—without editing plugin files or writing a custom template.

This method gives you complete layout control and makes your business directory look more professional and user-friendly.

If you’re building a business directory, custom listing platform, or Elementor-based marketplace, our team can handle the complete project—from data structure and custom templates to dynamic integrations and performance optimization.

You can Book a Free Project Consultation to discuss your requirements, timelines, and how we can deliver a scalable, production-ready solution for your directory website.

How to Create a Custom Popup in Divi Without Plugins Using Theme Builder

Popups are a great way to display offers, lead forms, promotions, or important messages. Most Divi users rely on third-party popup plugins, but the truth is—you can build a fully custom popup in Divi using only the Theme Builder, CSS, and a tiny line of jQuery.

The best part?

  • No extra plugins
  • Lightweight and fast
  • 100% design freedom
  • Works with any Divi page

This tutorial will walk you through creating a fully functional popup in Divi step-by-step.

Why Build Popups Without Plugins?

Using Divi alone gives you some big advantages:

  • Better page speed (no extra plugin loading)
  • Full control of styling with the Divi Visual Builder
  • No plugin conflicts
  • Reusable popup design for multiple pages
  • Works for WooCommerce, landing pages, and blog posts

Step-by-Step Guide to Creating a Popup in Divi

Follow these steps to build your custom popup from scratch:

Step 1: Create and Configure the Popup Section

  1. Open the page in Divi and enable the Visual Builder.
  2. Add a new Section where your popup will appear and design it with your content (text, image, form, button, blurb, etc.).
  3. Add Two rows Inside Section

Apply the following settings to the section:

  • Section Class : popup-modal
  • Section Background : transparent
  • Position (Advanced → Position) :
    • Position = Fixed
    • Z-Index = 9999

This section now acts as your main popup container and stays above all page content.

Step 2: Configure Two Rows Inside the Popup Section

Inside the popup section, create:

  • Row 1 → Popup Content
  • Row 2 → Overlay Background

Configure Row 1 (Popup Content)

Add your content modules such as:

  • Text or heading
  • Image
  • Button

Now add a close icon ( Divi Icon):

Set Icon Settings:

  • Icon Class : popup-trigger
  • Position (Advanced → Position) :
    • Position = Absolute
    • Z-Index = 11
    • Vertical/Horizontal Offset = 0px ( Set as per your need )

This positions the close icon on top of the popup.

Configure Row 2 (Overlay Background)

This will act as the background overlay to fade out the rest of the page.

Go to Row Settings and add:

  • Row Class : popup-overlay
  • Position (Advanced → Position) :
    • Position = Absolute
    • Z-Index = 9
    • Width = 100%
    • Height = 100%

Step 3: Hide the Popup on Page Load

Go to: Section Settings → Advanced → Custom CSS → Main Element

Add:  display: none;

This keeps the popup hidden until triggered.

Step 4: Add jQuery to Enable Popup Actions

Go to: Divi → Theme Options → Integration → Add code to <head>

Paste:

<script>
jQuery(function($){
  $('.popup-trigger').click(function(){
    $('.popup-overlay, .popup-modal').fadeIn();
  });

  $('.close-popup, .popup-overlay').click(function(){
    $('.popup-overlay, .popup-modal').fadeOut();
  });
});
</script>

Step 5: Add Popup Trigger Button

Finally, add a button anywhere on the page and give it this class: popup-trigger

This button will open the popup when clicked.

Test Now Popup Is Ready!

Now your popup will:

  • Open when the trigger button is clicked
  • Close when clicking the close icon
  • Close when clicking outside (overlay background)

Final Thoughts

Creating a popup in Divi without plugins gives you full flexibility and keeps your site lightweight. Once you’ve finished styling and testing, you can duplicate the layout and reuse it across multiple pages.

Custom popups built with Divi’s Theme Builder let you improve conversions without relying on heavy plugins. For a high-performing, professionally developed website, Book a Free Consultation.

Contact us

Let's Unleash Your Digital Potential Together.

Address

C-605, Ganesh glory 11, Nr. BSNL Office, Jagatpur Road, S.G. Highway, Jagatpur, Ahmedabad, India - 382481.

Phone

INDIA : (091) 8200639242 USA : +1 (310) 868-6009

Limited Time Offer

X

Try a Free 2-Hour Test Task

Experience our quality, speed, and communication on any small WordPress task before you commit. No contract. No cost. No obligation.
[For New Agency Partners]

"*" indicates required fields

Name*