WordPress script to set publish date to match created date

To set a WordPress post’s publish date to match its original creation date, you can run a one-time PHP script or add an action hook to your site’s 

functions.php file. This process is useful for backdating posts created from drafts or imported content, ensuring the correct date is displayed on the front end. 

Option 1: One-time script for all posts

Use this method to bulk update all existing posts. You can run it once by adding it to your theme’s functions.php file and then deleting it after the script runs. 

php

function set_publish_date_to_created_date() {
    <em>// Get all posts, pages, and custom post types.</em>
    $all_posts = get_posts(array(
        'post_type' => 'any',
        'posts_per_page' => -1, <em>// Get all posts</em>
        'post_status' => 'any',
        'orderby' => 'ID',
        'order' => 'ASC',
    ));

    foreach ($all_posts as $post) {
        <em>// Only update if the post's creation date (post_date) is different from the modified date (post_modified).</em>
        if ($post->post_date !== $post->post_modified) {
            $updated_post = array(
                'ID' => $post->ID,
                'post_date' => $post->post_date,
                'post_date_gmt' => $post->post_date_gmt,
            );
            wp_update_post($updated_post);
        }
    }
}
add_action('wp_loaded', 'set_publish_date_to_created_date');

How to use:

  1. Access your site’s files via FTP or cPanel.
  2. Navigate to your active theme’s folder, located at wp-content/themes/your-theme-name.
  3. Open the functions.php file and paste the code snippet at the bottom.
  4. Visit any page of your website to trigger the wp_loaded hook. The script will run automatically.
  5. After the page has loaded, remove the code from functions.php. The changes have already been applied to your database and the script is no longer needed.

Option 2: Automatically on post creation or update

This script uses the save_post action hook to update the publication date whenever a post is created or updated, ensuring the dates always match going forward. 

php

function update_publish_date_on_save($post_id, $post, $update) {
    <em>// Check if this is an update and not an initial creation.</em>
    if ($update) {
        <em>// Prevent infinite loops during the update process.</em>
        remove_action('save_post', 'update_publish_date_on_save', 10, 3);

        <em>// Get the original post data before the update.</em>
        $original_post = get_post($post_id);

        <em>// Prepare the updated post data.</em>
        $updated_post_data = array(
            'ID' => $post_id,
            'post_date' => $original_post->post_date,
            'post_date_gmt' => $original_post->post_date_gmt,
        );

        <em>// Update the post with the original creation date.</em>
        wp_update_post($updated_post_data);

        <em>// Re-add the hook.</em>
        add_action('save_post', 'update_publish_date_on_save', 10, 3);
    }
}
add_action('save_post', 'update_publish_date_on_save', 10, 3);

How to use:

  1. Navigate to wp-content/themes/your-theme-name.
  2. Open functions.php and paste the script at the bottom.
  3. Unlike the one-time script, this one is meant to be permanent. Save the file and the function will automatically run on every new post or update. 

Best practices

  • Use a child theme: When adding code to functions.php, use a child theme. If you update your main theme, any modifications you’ve made will be overwritten.
  • Create a site-specific plugin: For a cleaner approach, create a custom plugin to store your custom functions. This keeps your modifications separate from your theme.
  • Back up your site: Always back up your site’s database and files before running any scripts, especially one that performs a bulk update. 

I am looking to find all posts published today and change the publish date to the original creation date. Reason, I had a hundred posts that were completed but never published and I don’t want to lose the timeline of when I worked on posts

To change the publish date for all posts published today back to their original creation date, you can use a one-time PHP script

. The script should be added to your theme’s functions.php file, run once, and then removed. This approach is safer than a manual bulk edit, especially for a large number of posts. 

One-time script to fix today’s posts

Important: Before you begin, create a full backup of your website, including both files and the database.

  • Access your WordPress site’s files using an FTP client or your hosting provider’s file manager.
  • Navigate to your active theme’s folder, which is located in wp-content/themes/.
  • Find the functions.php file and open it for editing.
<code>function set_publish_date_for_today_posts() {  // Get the current date and time in the correct format for the query. 
  $today = date('Y-m-d'); 
  // Query for all posts published today. 
  $args = array( 'post_type' => 'post', 'posts_per_page' => -1, // Get all posts 
  'date_query' => array( 
    array( 
      'year' => date('Y'), 
      'month' => date('m'), 
      'day' => date('d'), 
    ), 
  ),       
  'post_status' => 'any', // Include all statuses (published, draft, etc.) 
  'fields' => 'ids', // Only retrieve post IDs for efficiency ); 
  $today_posts = get_posts($args); 
  // If there are posts to update, loop through them. 
  if (!empty($today_posts)) { 
    foreach ($today_posts as $post_id) { 
      $post_data = get_post($post_id, 'ARRAY_A'); 
      // Get the original creation date from the `post_date` database field. 
      $original_post_date = $post_data['post_date']; 
      // Prepare the post data for updating. 
      $updated_post = array( 'ID' => $post_id, 
      'post_date' => $original_post_date, 
      'post_date_gmt' => get_gmt_from_date($original_post_date), ); 
      // Update the post with the original creation date. 
      wp_update_post($updated_post); 
    } 
  } 
} 

// Add an action hook to run the function when the site is loaded. 
add_action('wp_loaded', 'set_publish_date_for_today_posts');
  • Save the functions.php file.
  • Visit any page on your website to execute the wp_loaded hook and run the script.
  • Once the script has executed, delete the code you added from functions.php.
    It is a temporary script and should not be left in your theme’s files. 

How the script works

  • date('Y-m-d'): This gets the current date to query for posts published today.
  • get_posts(): This function retrieves the IDs of all posts published on the current day, regardless of their status.
  • get_post(): This gets the full data for each post, including the original post_date from when it was first drafted or created.
  • wp_update_post(): This function safely updates each post with its original creation date, ensuring that all other post data remains unchanged. 

creating a “dry run” version of the script. This approach prevents accidental modifications by replacing the database-altering function, wp_update_post(), with a harmless one that simply outputs the changes that would be made. 

Step 1: Back up your site

Before making any changes, it is critical to perform a full backup of your WordPress site. Use a reliable backup plugin or your hosting provider’s backup tools to save both your files and database. 

Step 2: Add the dry run script to your functions.php

Access your theme’s functions.php file via SFTP or your hosting provider’s file manager and add the following code. It is highly recommended to do this on a child theme to prevent your changes from being overwritten during a theme update. 

php

function set_publish_date_for_today_posts_dry_run() {
    <em>// Get the current date and time in the correct format.</em>
    $today = date('Y-m-d');

    <em>// Query for all posts published today.</em>
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);
    
    echo '<pre>'; <em>// Pre-formatted output for readability</em>

    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $original_post_date = $post_data['post_date'];

            <em>// Log the proposed changes instead of performing them.</em>
            echo '<h3>Post ID: ' . $post_id . '</h3>';
            echo 'Current Publish Date: ' . $post_data['post_date'] . '<br>';
            echo 'Original Creation Date: ' . $original_post_date . '<br>';
            echo '<b>Would be changed to: ' . $original_post_date . '</b><br><br>';
        }
    } else {
        echo 'No posts published today were found.';
    }
    
    echo '</pre>';
}
<em>// Add an action hook to run the function when a page loads.</em>
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run');

Step 3: Run the dry run and verify the results

  1. Save the file and visit any page on your website while logged in as an administrator.
  2. Inspect the output. You will see a list of posts that match the query, along with the “before” and “after” dates. The script will simply display this information and not make any changes. 

Step 4: Run the live script

Once you have confirmed that the query is correct and identifies the right posts, you can safely proceed with the actual changes.

  1. Remove the dry run script from your functions.php file.
  2. Add the live script from the previous answer.
  3. Run the script by visiting any page on your site.
  4. Remove the live script from functions.php after it has run. 

how can I get the post title for review?

To display the post titles during the dry run, you simply need to access the 

post_title property of the post data object. You can enhance the previous dry run script to include the title, which provides a much clearer picture of which posts would be affected by the script.

Enhanced dry run script with post titles

This updated version of the dry run script fetches the post data for each post published today and outputs its title, ID, current publish date, and original creation date.

Important: Remember to back up your site before making any changes.

  1. Access your functions.php file via SFTP or your hosting provider’s file manager.
  2. Replace the previous dry run code with this enhanced version: 

php

function set_publish_date_for_today_posts_dry_run() {
    <em>// Get today's date.</em>
    $today = date('Y-m-d');

    <em>// Query for all posts published today.</em>
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);

    echo '<pre>'; <em>// Pre-formatted output for readability</em>

    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $original_post_date = $post_data['post_date'];
            $post_title = $post_data['post_title']; <em>// Get the post title</em>

            <em>// Log the proposed changes.</em>
            echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
            echo 'Post ID: ' . $post_id . '<br>';
            echo 'Current Publish Date: ' . $post_data['post_date'] . '<br>';
            echo 'Original Creation Date: ' . $original_post_date . '<br>';
            echo '<b>Would be changed to: ' . $original_post_date . '</b><br><br>';
        }
    } else {
        echo 'No posts published today were found.';
    }

    echo '</pre>';
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run');
  1. Save the file and visit any page on your website while logged in as an administrator. 

How it works

  • $post_title = $post_data['post_title'];: After fetching the post data into the $post_data array, you can simply access the post_title key to retrieve the post’s title.
  • esc_html($post_title): This is a standard WordPress security function that sanitizes the title for safe output, preventing any HTML from being rendered incorrectly.
  • echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';: This line displays the post title in the browser, making it easy to identify which posts are being processed. 

After you have verified the list of posts is correct, you can safely proceed with running the live script provided in the previous answers. Be sure to remove both the dry run and live scripts from your functions.php file when you are finished.

I used WPCode plugin to add php code and set to Admin but it not producing any output. How can I debug what happened?

There are several reasons a WPCode snippet might not produce output, even with the “Admin” location set. This often comes down to timing, execution context, or hidden PHP errors. Since you are not seeing any output, follow these debugging steps to diagnose the issue

Step 1: Check WPCode’s error logs

WPCode has a built-in error logging system that can help you pinpoint the exact problem with your script. 

  1. Enable error logging: Go to Code Snippets > Settings in your WordPress admin.
  2. Navigate to the Error Logging tab and turn on the toggle.
  3. Click the Save Changes button.
  4. Run the script again: Reload the page in the admin area to re-run your snippet.
  5. Check the logs: Go to Code Snippets > Tools > Logs. Review the logs for any errors related to your snippet. If there is a fatal error, WPCode may have automatically disabled the snippet to prevent your site from breaking. 

Step 2: Enable general WordPress debugging

For more detailed information, you can enable WordPress’s built-in debugging features. This will record all PHP errors, notices, and warnings to a log file. 

  1. Edit your wp-config.php file: Access your site’s files via FTP or your hosting’s file manager.
  2. Locate the wp-config.php file in the root directory and add the following lines before the line /* That's all, stop editing! Happy blogging. */:phpdefine( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true ); define( 'WP_DEBUG_DISPLAY', false ); <em>// Hide errors from the front end</em> Use code with caution.
  3. Run the script again: Reload your admin page.
  4. Check the debug.log file: A file named debug.log will be created in your /wp-content/ directory. Check its contents for any output or errors related to your script. 

Step 3: Verify the location and hook

Simply setting the snippet location to “Admin” is not enough. You also need to ensure your code is running on an appropriate hook that executes when you expect it to. The wp_loaded hook is generally a safe bet for admin-only scripts.

  1. Edit your WPCode snippet and confirm the PHP code starts with the add_action() function.
  2. Check that the location is set to Admin Only.
  3. Add or modify the snippet to use the wp_loaded hook. This ensures it runs after WordPress has loaded everything, but before any output is sent.phpadd_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run'); function set_publish_date_for_today_posts_dry_run() { <em>// Your code...</em> } Use code with caution.
  4. Save the snippet and reload your admin page. 

Step 4: Add explicit logging to the script

To isolate the issue, you can add explicit logging to the dry run script to trace its execution and check if the get_posts() query is returning any results. 

php

function set_publish_date_for_today_posts_dry_run() {
    <em>// Log the function has been called</em>
    error_log('Dry run script initiated.');

    <em>// Get today's date.</em>
    $today = date('Y-m-d');

    <em>// Query for all posts published today.</em>
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);

    <em>// Log the query results</em>
    error_log('Query for posts published today returned: ' . count($today_posts) . ' posts.');

    <em>// Output for Admin users</em>
    if (current_user_can('manage_options')) {
        echo '<pre>';
        echo '<h2>Dry Run: Posts that would be updated:</h2>';
        if (!empty($today_posts)) {
            foreach ($today_posts as $post_id) {
                $post_data = get_post($post_id, 'ARRAY_A');
                $original_post_date = $post_data['post_date'];
                $post_title = $post_data['post_title'];

                echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
                echo 'Post ID: ' . $post_id . '<br>';
                echo 'Current Publish Date: ' . $post_data['post_date'] . '<br>';
                echo 'Original Creation Date: ' . $original_post_date . '<br>';
                echo '<b>Would be changed to: ' . $original_post_date . '</b><br><br>';
            }
        } else {
            echo 'No posts published today were found.';
        }
        echo '</pre>';
    }
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run');

After implementing these steps, re-check the WPCode logs, the /wp-content/debug.log file, and your admin dashboard to see if the script is now producing output or generating errors. 

PHP Warning Undefined array key “headers_footers_mode” Plugin: WPCode Lite File: /wp-content/plugins/insert-headers-and-footers/includes/admin/pages/class-wpcode-admin-page-settings.php Line: 322

The PHP warning 

Undefined array key "headers_footers_mode" suggests that the WPCode plugin is trying to read a setting that doesn’t exist in its configuration, likely due to an incomplete or failed update. This is a common issue and is not a fatal error, but it does indicate a problem that can be easily resolved. 

Cause of the warning

WPCode was previously known as “Insert Headers and Footers.” During the transition, a “Simple mode” was available that allowed users to continue using the plugin for only header and footer scripts. The warning appears when the code tries to check for this legacy setting, and the value isn’t present in the database. 

How to resolve the warning

Option 1: Re-save WPCode settings

The most common and easiest fix is to simply navigate to the WPCode settings page and save the settings again. This will prompt the plugin to create or update the missing database key.

  1. Log in to your WordPress admin dashboard.
  2. Go to Code Snippets > Settings.
  3. Without making any changes, click the Save Changes button in the top right corner.
  4. The warning should no longer appear on subsequent page loads. 

Option 2: Re-activate the plugin

If saving the settings doesn’t work, re-activating the plugin can force it to reset its database settings.

  1. In your WordPress admin dashboard, navigate to Plugins > Installed Plugins.
  2. Find WPCode – Insert Headers and Footers + Custom Code Snippets.
  3. Click Deactivate.
  4. Immediately after, click Activate. This process should run the necessary upgrade routines and resolve the issue. 

How to handle potential future issues

  • Keep WPCode updated: The warning is most often associated with old versions or a specific upgrade path. Make sure your plugin is always running the latest version to prevent future issues.
  • Check for conflicting plugins: Although unlikely to be related to this specific warning, plugin conflicts can sometimes cause settings to fail. If the problem persists, you can use a plugin like Health Check & Troubleshooting to temporarily isolate plugins and diagnose the problem.
  • Reach out to WPCode support: If neither solution works, you can contact the plugin’s support team on the WordPress.org forums. They can provide guidance specific to your installation. 

Instead of original post date, I need creation date

In WordPress, the “original post date” is the same as the “creation date.” Both refer to the 

post_date field in the database, which is the time a post was first created. 

The key distinction is between post_date and post_modified.

  • post_date (post_date_gmt in GMT) is the creation date.
  • post_modified (post_modified_gmt in GMT) is the last time the post was updated. 

The dry-run script you used correctly fetches the post_date, so no changes are needed to get the creation date. To confirm this, you can compare the post_date and post_modified values for posts you know were updated recently. 

This updated script will display the post’s title, ID, its current published date (post_date), and the last modified date (post_modified). This will help you verify that the post_date holds the true original creation date and that it differs from the post_modified date for posts you edited. 

Important: Back up your site before adding or running any code.

  1. Access your functions.php file via SFTP or your hosting provider’s file manager.
  2. Replace the previous dry-run code with this enhanced version:

php

function set_publish_date_for_today_posts_dry_run() {
    <em>// Get today's date.</em>
    $today = date('Y-m-d');

    <em>// Query for all posts published today.</em>
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);

    echo '<pre>'; <em>// Pre-formatted output for readability</em>

    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts published today that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $original_post_date = $post_data['post_date'];
            $last_modified_date = $post_data['post_modified']; <em>// Get the last modified date</em>
            $post_title = $post_data['post_title'];

            echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
            echo 'Post ID: ' . $post_id . '<br>';
            echo 'Current Publish Date (post_date): ' . $original_post_date . '<br>';
            echo 'Last Modified Date (post_modified): ' . $last_modified_date . '<br>';
            echo '<b>Would be changed to: ' . $original_post_date . '</b><br><br>';
        }
    } else {
        echo 'No posts published today were found.';
    }

    echo '</pre>';
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run');
  1. Save the file and visit any page in your admin dashboard while logged in as an administrator. 

This output will clearly show the post’s creation (post_date) and last modified (post_modified) timestamps, confirming that you are targeting the correct date for your posts.
After confirming, you can use the live script from the previous answer to perform the bulk update. 

The results from preview script have the same date/time:
Post Title: 2025_07_21 Dream
–Current Publish Date: 2025-10-09 09:25:17
–Original Creation Date: 2025-10-09 09:25:17
Would be changed to: 2025-10-09 09:25:17
Post ID: 3194 Post Title: Who owns the all the shovels
–Current Publish Date: 2025-10-09 09:23:30
–Original Creation Date: 2025-10-09 09:23:30
Would be changed to: 2025-10-09 09:23:30
Post ID: 3196 Post Title: UNRAID – Tips & Tricks
–Current Publish Date: 2025-10-09 09:22:58
–Original Creation Date: 2025-10-09 09:22:58
Would be changed to: 2025-10-09 09:22:58

Based on the preview script output, it appears the “original creation date” is the same as the “current publish date.” This is the expected behavior for posts that have been drafted and completed recently and were never scheduled for a future date

The post_date field in WordPress stores the post’s creation time. When a post is first created and saved as a draft, its post_date is set. When you later publish that post on the same day, WordPress typically updates the post_date to the time of publication, essentially overwriting the original creation time with the publish time. 

To recover the true original creation date, you need to find an earlier timestamp. There are two primary methods for this, but both have limitations:

Method 1: Check the post_modified date

If you only saved the posts as drafts once and never modified them again until today’s mass-publish, then the post_modified field might hold the original creation date. However, if you made any changes to the drafts over time, the post_modified date will also have been updated. 

Dry-run script to compare dates

This script will add the post_modified date to the output for comparison.

Important: Back up your site and add this script using a plugin like WPCode. 

php

function set_publish_date_for_today_posts_dry_run_with_modified() {
    $today = date('Y-m-d');
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);
    echo '<pre>';
    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts published today that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $original_post_date = $post_data['post_date'];
            $last_modified_date = $post_data['post_modified'];
            $post_title = $post_data['post_title'];

            echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
            echo 'Post ID: ' . $post_id . '<br>';
            echo 'Current Publish Date (post_date): ' . $original_post_date . '<br>';
            echo 'Last Modified Date (post_modified): ' . $last_modified_date . '<br>';
            echo '<br>';
        }
    } else {
        echo 'No posts published today were found.';
    }
    echo '</pre>';
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run_with_modified');

After you run this script, compare the Current Publish Date with the Last Modified Date.
If the Last Modified Date is earlier and corresponds to the time the posts were originally created, you can use that field to update the posts. 

Method 2: Check the post revisions

If you have revisions enabled in WordPress, the original creation date may be preserved in the _wp_old_date post meta field or in an earlier revision. This is the most reliable method for recovering a date that has been changed. 

Script to retrieve the earliest revision date

This is a more complex dry-run script that queries the database for the earliest revision date of a post, as long as revisions are enabled. 

Important: Back up your site and run this script via WPCode.

php

function get_earliest_revision_date($post_id) {
    global $wpdb;
    $revision_id = $wpdb->get_var($wpdb->prepare(
        "SELECT MIN(ID) FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'",
        $post_id
    ));

    if ($revision_id) {
        return $wpdb->get_var($wpdb->prepare(
            "SELECT post_date FROM $wpdb->posts WHERE ID = %d",
            $revision_id
        ));
    }
    return null;
}

function set_publish_date_for_today_posts_dry_run_with_revision() {
    $today = date('Y-m-d');
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);
    echo '<pre>';
    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts published today that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $original_post_date = $post_data['post_date'];
            $post_title = $post_data['post_title'];
            $earliest_revision_date = get_earliest_revision_date($post_id);

            echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
            echo 'Post ID: ' . $post_id . '<br>';
            echo 'Current Publish Date: ' . $original_post_date . '<br>';
            echo 'Original Creation Date from Earliest Revision: ' . ($earliest_revision_date ? esc_html($earliest_revision_date) : 'Not found') . '<br>';
            echo '<br>';
        }
    } else {
        echo 'No posts published today were found.';
    }
    echo '</pre>';
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run_with_revision');

This second script will give you the most accurate original creation date.
After confirming the output, you can modify the final “live” script to use the earliest revision date instead of the post_date.

Does wordpress not store the actual creation date?
Post Title: Python Virtual Environment
–Current Publish Date: 2025-10-09 08:49:20
–Original Creation Date: 2025-10-09 08:49:20
–Last Modified Date (post_modified): 2025-10-09 08:49:20
Would be changed to: 2025-10-09 08:49:20
Post ID: 3369 Post Title: haproxy reverse engineering
–Current Publish Date: 2025-10-09 08:47:52
–Original Creation Date: 2025-10-09 08:47:52
–Last Modified Date (post_modified): 2025-10-09 08:47:52
Would be changed to: 2025-10-09 08:47:52

The short answer is that 

WordPress’s built-in system does not reliably store a permanent, immutable “creation date” separate from the post_date. The post_date field is overwritten when you manually publish or update a post, even if it was previously saved as a draft. 

Here’s a breakdown of why you are seeing the same dates and what your options are.

How WordPress handles dates

  • post_date: This is the date a post is published, or, for drafts, the date it was created. However, if a draft is published manually, the post_date is updated to the publish date and time.
  • post_modified: This is the date and time a post was last updated or changed. Since you just manually published all the posts, both the post_date and post_modified are now identical, reflecting the time you hit “Publish”.
  • No separate “creation date” field: There is no distinct original_creation_date field in the standard WordPress database. This is a common point of confusion for users who backdate content or import from other systems. 

Where to find the original date

Since the built-in fields won’t give you what you need, your best bet is to look at older post revisions. Assuming you didn’t publish all the posts simultaneously from a freshly imported set, the earliest revision of each post should have a date that is closer to the original creation time.

Script to retrieve the earliest revision date

This script builds on your dry-run and queries the database for the earliest revision date of a post, as long as revisions are enabled. 

Important: Back up your site and run this script via a plugin like WPCode. 

php

function get_earliest_revision_date($post_id) {
    global $wpdb;
    $revision_id = $wpdb->get_var($wpdb->prepare(
        "SELECT MIN(ID) FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'",
        $post_id
    ));

    if ($revision_id) {
        return $wpdb->get_var($wpdb->prepare(
            "SELECT post_date FROM $wpdb->posts WHERE ID = %d",
            $revision_id
        ));
    }
    return null;
}

function set_publish_date_for_today_posts_dry_run_with_revision() {
    $today = date('Y-m-d');
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);
    echo '<pre>';
    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts published today that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $post_title = $post_data['post_title'];
            $earliest_revision_date = get_earliest_revision_date($post_id);

            echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
            echo 'Post ID: ' . $post_id . '<br>';
            echo 'Current Publish Date: ' . $post_data['post_date'] . '<br>';
            echo 'Original Creation Date from Earliest Revision: ' . ($earliest_revision_date ? esc_html($earliest_revision_date) : 'Not found') . '<br>';
            if ($earliest_revision_date) {
                echo '<b>Would be changed to: ' . esc_html($earliest_revision_date) . '</b><br><br>';
            } else {
                echo '<b>No change possible. Revisions not available.</b><br><br>';
            }
        }
    } else {
        echo 'No posts published today were found.';
    }
    echo '</pre>';
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run_with_revision');

This will likely show different dates, giving you the information you need to proceed with confidence.

Final steps

  1. Run the dry-run script. Check the output to see if the earliest revision dates are correct.
  2. Modify the live script. Replace the post_date with the date from the earliest revision, if found.
  3. Run the live script to update your posts.
  4. Delete the script after it runs. 

my wordpress has a prefix of wp, so table was wp_posts:
| ID | post_author | post_date | post_date_gmt | post_content | post_title | post_excerpt | post_status | comment_status | ping_status | post_password | post_name | to_ping | pinged | post_modified | post_modified_gmt | post_content_filtered | post_parent | guid | menu_order | post_type | post_mime_type | comment_count |
I think the data may be in the wp_postmeta table:
| meta_id | post_id | meta_key | meta_value | 1282 | 1040 | _wp_old_date | 2023-04-17

You are correct that WordPress stores the old date in the  wp_postmeta table under the _wp_old_date key. This happens automatically when a user changes a post’s publish date in the editor. The earlier dry-run script was looking for the original date in the post_date column, which, as you discovered, was overwritten during publication. 

Here is a revised script that will retrieve the post’s title, its current publish date, and the original creation date from the _wp_old_date post meta key. 

Dry-run script to find the old date in post meta

Important: Back up your site before adding or running any code.

  1. Access your functions.php file via SFTP or your hosting provider’s file manager, or use your WPCode plugin.
  2. Add the following code. It will check for the existence of the _wp_old_date key and display that value instead of the overwritten post_date

php

function get_old_post_date($post_id) {
    <em>// get_post_meta returns an array for multiple values, use [0] for the first</em>
    $old_date = get_post_meta($post_id, '_wp_old_date', true);
    return $old_date ? $old_date : null;
}

function set_publish_date_for_today_posts_dry_run_with_meta() {
    $today = date('Y-m-d');
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'year'  => date('Y'),
                'month' => date('m'),
                'day'   => date('d'),
            ),
        ),
        'post_status'    => 'any',
        'fields'         => 'ids',
    );

    $today_posts = get_posts($args);
    echo '<pre>';
    if (!empty($today_posts)) {
        echo '<h2>Dry Run: Posts published today that would be updated:</h2>';
        foreach ($today_posts as $post_id) {
            $post_data = get_post($post_id, 'ARRAY_A');
            $current_publish_date = $post_data['post_date'];
            $post_title = $post_data['post_title'];
            $original_creation_date = get_old_post_date($post_id);

            echo '<h3>Post Title: ' . esc_html($post_title) . '</h3>';
            echo 'Post ID: ' . $post_id . '<br>';
            echo 'Current Publish Date: ' . esc_html($current_publish_date) . '<br>';
            if ($original_creation_date) {
                echo 'Original Creation Date (from meta): ' . esc_html($original_creation_date) . '<br>';
                echo '<b>Would be changed to: ' . esc_html($original_creation_date) . '</b><br><br>';
            } else {
                echo 'Original Creation Date (from meta): Not found<br>';
                echo '<b>No change possible. `_wp_old_date` meta key not found.</b><br><br>';
            }
        }
    } else {
        echo 'No posts published today were found.';
    }
    echo '</pre>';
}
add_action('wp_loaded', 'set_publish_date_for_today_posts_dry_run_with_meta');

How this script works

  • get_old_post_date($post_id): This helper function uses WordPress’s get_post_meta() function to retrieve the value stored under the _wp_old_date key for a given post ID.
  • get_post_meta($post_id, '_wp_old_date', true): The true parameter ensures the function returns a single value directly, rather than an array.
  • $original_creation_date = get_old_post_date($post_id);: This line calls the helper function to fetch the meta date for each post found in today’s query.
  • Conditional Output: The script checks if an old date was found in the post meta. If it exists, it displays what the new date will be. If not, it informs you that no change can be made. 

Running the dry-run and live scripts

  1. Run the dry-run script: Add the code above via your WPCode plugin and visit a page in the admin area to see the output.
  2. Inspect the output: Verify that the “Original Creation Date (from meta)” matches what you expect. If it does, you can proceed.
  3. Use the live script: If the dates are correct, swap the dry-run script for this live version which will update the posts.phpfunction set_publish_date_for_today_posts_live() { $today = date('Y-m-d'); $args = array( 'post_type' => 'post', 'posts_per_page' => -1, 'date_query' => array( array( 'year' => date('Y'), 'month' => date('m'), 'day' => date('d'), ), ), 'post_status' => 'any', 'fields' => 'ids', ); $today_posts = get_posts($args); if (!empty($today_posts)) { foreach ($today_posts as $post_id) { $original_creation_date = get_post_meta($post_id, '_wp_old_date', true); if ($original_creation_date) { $updated_post = array( 'ID' => $post_id, 'post_date' => $original_creation_date, 'post_date_gmt' => get_gmt_from_date($original_creation_date), ); wp_update_post($updated_post); } } } } add_action('wp_loaded', 'set_publish_date_for_today_posts_live'); Use code with caution.
  4. Delete the live script after it runs successfully. 

Getting Close:

Post Title: vi tricks Post ID: 3387
–Current Publish Date: 2025-10-09 08:52:37
–Original Creation Date (from meta): Not found No change possible. `_wp_old_date` meta key not found.
Post Title: HAPROXY MAP FILE Post ID: 3395
–Current Publish Date: 2025-10-09 08:51:35
–Original Creation Date (from meta): Not found No change possible. `_wp_old_date` meta key not found.
Post Title: Generate Random String Post ID: 3391
–Current Publish Date: 2025-10-09 08:50:36
–Original Creation Date (from meta): 2025-10-06 Would be changed to: 2025-10-06
Post Title: SSH into Windows 11 Post ID: 3414
–Current Publish Date: 2025-10-09 08:50:03
–Original Creation Date (from meta): 2025-10-08 Would be changed to: 2025-10-08
Post Title: Python Virtual Environment Post ID: 3421
–Current Publish Date: 2025-10-09 08:49:20
–Original Creation Date (from meta): 2025-10-08 Would be changed to: 2025-10-08
Post Title: haproxy reverse engineering Post ID: 3369
–Current Publish Date: 2025-10-09 08:47:52
–Original Creation Date (from meta): 2025-10-06 Would be changed to: 2025-10-06 select * from wp_postmeta where post_id=3369;
+———+———+————–+————–+
| meta_id | post_id | meta_key | meta_value |
+———+———+————–+————–+
| 8168 | 3369 | _edit_lock | 1760017691:2 |
| 8226 | 3369 | _wp_old_date | 2025-10-06 |
+———+———+————–+————–+
2 rows in set (0.000 sec)
Do you know the syntax for _edit_lock and why some posts are missing the _wp_old_date?
select * from wp_postmeta where post_id=3395;
+———+———+————+————–+
| meta_id | post_id | meta_key | meta_value |
+———+———+————+————–+
| 8184 | 3395 | _edit_lock | 1760038694:2 |
+———+———+————+————–+
1 row in set (0.000 sec)

_edit_lock

 meta key

The _edit_lock meta key is not related to post dates. It is a feature used by WordPress to prevent editing conflicts on multi-author sites. 

  • Syntax: The value is stored in the format timestamp:user_id. The timestamp indicates when the post was last locked, and the user_id is the ID of the user who is currently editing it.
  • Purpose: It’s part of the Heartbeat API and is updated every 15 seconds while a user is editing a post. If another user tries to edit the same post, they will see a notification indicating it is locked. 

Why some posts are missing _wp_old_date

The _wp_old_date meta key is not a permanent record of a post’s initial creation date. It is created only when a post’s publish date is manually changed in the editor. If the publish date was never changed from its original value, this meta key will not exist. 

Here are a few reasons why the posts in your example,
“vi tricks” and “HAPROXY MAP FILE,” are missing this meta key:

  • Never manually backdated: The most likely reason is that you did not manually change the publish date for these specific posts. When you bulk-published all of the posts today, WordPress simply used the current date and time without first creating an old date record.
  • Initial creation and publication: If a post was created and published on the same day without any manual date changes, WordPress would not need to create an old date meta key.
  • Import process: If the posts were imported from another system, the import process may have set the post_date field directly without creating the _wp_old_date meta key. 

Summary of findings

  • Posts like “Generate Random String” have a _wp_old_date because you or a co-author likely changed the publication date manually at some point.
  • Posts like “vi tricks” have no _wp_old_date because their post_date was not manually changed until the bulk publication occurred today.
  • The _edit_lock meta key is a separate and unrelated feature. 

Next step: Find another date source

Since the _wp_old_date is unreliable for posts that have never had their publication date manually changed, you have two remaining options to find a more accurate creation date:

  1. Post Revisions: As discussed previously, the earliest post revision’s date is often a good indicator of the original creation date. You can run the revised dry-run script that checks post revisions.
  2. External Records: If you don’t have revisions, your original creation date may be lost forever in WordPress. In this case, you will need to rely on external records if you have them, such as a spreadsheet or file system creation date. 

I should be able to get the dates from a backup prior to today.

That’s an excellent approach. Using a database backup from before today’s bulk publication is the most reliable way to recover the original 

post_date values. 

Method: Compare the wp_posts tables

Since you have access to the database via a tool like phpMyAdmin, you can compare the post_date values in the backup’s wp_posts table with your live site’s wp_posts table. This approach is safer than restoring the entire database. 

Here’s a step-by-step guide:

Step 1: Export the current posts’ data

Run this query on your live site’s database to create a temporary table of all posts and their dates after the bulk publish. This is a snapshot of the current state. 

CREATE TABLE wp_temp_post_dates AS
SELECT ID, post_date, post_title
FROM wp_posts
WHERE post_type = 'post';

Step 2: Import the backup wp_posts table

Create a new, temporary database or a new set of tables for your backup data. This prevents you from accidentally overwriting your current site. You can use a name like wp_posts_backup

Step 3: Compare the dates

Run a query to find the original post_date from the backup for each post. 

SELECT
    t1.ID,
    t1.post_title,
    t1.post_date AS current_publish_date,
    t2.post_date AS original_creation_date
FROM
    wp_temp_post_dates AS t1
JOIN
    wp_posts_backup AS t2 ON t1.ID = t2.ID
WHERE
    t1.post_date != t2.post_date;

This query joins your temporary and backup tables on the post ID and will only show you posts where the date has changed, isolating the posts you just published. 

Step 4: Generate the update script

You can then generate a list of UPDATE statements to apply the original dates from the backup to your live site. 

SELECT CONCAT(
    "UPDATE wp_posts SET post_date = '",
    t2.post_date,
    "', post_date_gmt = '",
    t2.post_date_gmt,
    "' WHERE ID = ",
    t1.ID,
    ";"
)
FROM
    wp_temp_post_dates AS t1
JOIN
    wp_posts_backup AS t2 ON t1.ID = t2.ID
WHERE
    t1.post_date != t2.post_date;

This will produce a list of commands like this:

UPDATE wp_posts SET post_date = '2025-10-06 00:00:00', post_date_gmt = '2025-10-06 04:00:00' WHERE ID = 3391;
UPDATE wp_posts SET post_date = '2025-10-08 00:00:00', post_date_gmt = '2025-10-08 04:00:00' WHERE ID = 3414;
...

Step 5: Run the update

Copy the generated UPDATE statements and execute them on your live site’s database. 

Step 6: Clean up

After you’re finished, delete your temporary tables to clean up your database. 

DROP TABLE wp_temp_post_dates;
DROP TABLE wp_posts_backup;

Leave a Reply