There are situations where you would need to automatically set WordPress post title on post save. One situation I had was the list of past newsletters sent by client’s company. We had month and issue number information set in ACF fields because we needed that info separately for front-end display and it would be unnecessarily to set the same info in post title. So here’s how I did it.

Setting automatic WordPress post title

Firstly in PHP code for custom post type we want to remove the post title field in post editor because we don’t need it.

<?php
add_action( 'init', 'register_cpt_newsletter' );
function register_cpt_newsletter() {
    $labels = array( 
        // ...
    );

    $args = array( 
        // ...
        'supports' => array( 'custom-fields', 'thumbnail' ),
        // note there is no 'title' in the array above
    );

    register_post_type( 'newsletter', $args );
}

Ok, after we have that in place we will hook into the wp_insert_post_data.

<?php
add_filter('wp_insert_post_data', function($data, $id) {
    // Check for the correct post type
    if ($data['post_type'] == 'newsletter') {
            // Month
            $field = get_field_object('issue_month');
            $month_slug = $field['key'];
            // Year
            $field = get_field_object('issue_year');
            $year_slug = $field['key'];
            // Issue Number
            $field = get_field_object('issue_number');
            $issue_slug = $field['key'];

        $data['post_title'] = $_POST['acf'][$month_slug] . " " . $_POST['acf'][$year_slug] . " / Issue " . $_POST['acf'][$issue_slug];
    }

    return $data;
}, 10, 2);

While most of the code is pretty straightforward you might be wondering about the lines 6 and 7:

            // Month
            $field = get_field_object('issue_month');
            $month_slug = $field['key'];

If you would be inspecting POST request that saves the post you would notice that ACF fields, in my case issue_month, issue_year and issue_number, have somewhat different field names. For example first field had the key which sounds pretty random, something like acf[field_5e2b14eb33d45]. Yes, ACF uses something completely different under the hood then it is showing us on the field editor.

Ok, we could hardcode that field name but how can we be sure once we deploy site to live server that we will have exactly the same field name? We can’t, that’s why we need a bulletproof way of getting that field name. That’s why we are using get_field_object function which will get us that info for each ACF field.

Ok, we have everything in place, we test it by saving our newsletter custom post type and voilĂ  – our post automatically gets the title “September 2020 / Issue 123”.