Introduction
I was recently generating some posts for a custom post type that includes ACF fields using WP All Import based on a CSV file I created.
The generation of the posts went fine, and the custom ACF fields seemed to be populated properly by WP All Import. There were some issues when trying to use the fields in my templates though.
Problem description
After importing my CSV using WP All Import, the posts were created and the ACF custom field was populated in the admin UI or backend.
I have an Elementor single page template which I use for this custom post type, where I want to use the ACF custom field in the “Title” and in the “Text Editor” elements.
The problem is that I could retrieve the ACF field for the “Title”, but not in the “Text Editor” when using the ACF shortcodes.
The first way of retrieving the field works, but the shortcode one does not.
As you can see in the admin UI, the field does actually exist and is populated:
Solution
You have two options here:
- Save every post one by one manually through the admin UI
- Loop over the posts through Python and update each one
I have over 300 posts, so I opted for automation through Python and the WordPress REST API.
Prerequisites
Make sure you have the option “Show in REST API” enabled for your ACF Field Group.
You will also need to create a password for the WordPress REST API under Users -> Profile -> Application Passwords. Remember this password for later.
Python code
I used Python and the WordPress REST API to solve this.
You can use the following code and adjust to your needs. You will have to change:
- API URL
- CPT in the URL
- ACF fields
The way this script works is:
- Retrieve all posts of a certain custom post type
- For each post: get the ID and all the custom fields that -> this data is saved to variables
- For each post: update the post (based on the ID from earlier) with all the custom fields as data
You could probably just add a tag instead of reading/saving all the ACF fields again, but I haven’t tried this. You could also automate the retrieval of the ACF tags, but for me it was a one-time use, so I didn’t bother.
from tqdm import tqdm
import requests
from urllib3.exceptions import InsecureRequestWarning
import base64
import json
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# GLOBAL VARS
wordpress_user = "Your username which you created the application password for"
wordpress_password = "Your password (including the spaces)"
wordpress_credentials = wordpress_user + ":" + wordpress_password
wordpress_token = base64.b64encode(wordpress_credentials.encode())
wordpress_header = {'Authorization': 'Basic ' + wordpress_token.decode('utf-8')}
def page_numbers():
"""Infinite generate of page numbers"""
num = 1
while True:
yield num
num += 1
def get_posts():
posts = []
api_url = 'https://YOUR-DOMAIN.be/wp-json/wp/v2/YOUR-CPT-NAME'
for page in tqdm(page_numbers()):
# Fetch the next [pagesize=10] posts
posts_page = requests.get(api_url, headers=wordpress_header, params={"page": page, "per_page": 100}, verify=False).json()
# Check for "last page" error code
if isinstance(posts_page, dict) and posts_page["code"] == "rest_post_invalid_page_number": # Found last page
break
# No error code -> add posts
posts += posts_page
return posts
def save_post(posts):
base_api_url = 'https://YOUR-DOMAIN.be/wp-json/wp/v2/YOUR-CPT-NAME/'
# This will retrieve the populated ACF field first and save it to a variable
# This data is then used to save it to the post again
for post in tqdm(posts):
# Get the needed ACF fields
# Get ID and regio
id = str(post['id'])
regio = post['acf']['regio']
# ADD YOUR ACF FIELDS HERE - DELETE REGIO
# WP REST API data obj
data = {
"acf": {
"regio": regio
# ADD YOUR ACF FIELDS HERE - DELETE REGIO
}
}
# Update CPT
response = requests.post(base_api_url + id, headers=wordpress_header, json=data, verify=False)
if response.status_code != 200:
print("ERROR: API returned non 200")
break
if __name__ == '__main__':
# Get all posts for CPT
posts = get_posts()
# Save all posts with CPT data to fix bug in WP All Import
save_post(posts)