How to create and update Custom Posts from API data (JSON, XML, CSV, …)
You can create Custom Post Pages (CPP) from Custom Post Types (CPT) and API data (JSON, XML, CSV, …) by assembling a shortcode. This method is described here: Shortcode for creating Custom Post Pages out of Custom Post Types out of JSON.
Here, we take a different approach.
The major advantage: an easier and more flexible way to update Custom Pages, without the need for complex shortcode building.
The “disadvantage” of having full control: this method requires a more programmatic approach.
Step 1: Create a “Custom Post Type” (CPT)
You can create CPTs in many ways. In this example we use the free Plugin “Custom Post Type UI“.
With that plugin, we create a CPT with slug (also used as the Singular Label) “meetupevent”, which is linked to the taxonomy with the slug “meetupeventtax”.
Using Advanced Custom Fields (ACF), we then add the Custom Post Fields (CPF):
- “nameofevent”, “statusofevent”, and “venueofevent” as simple text fields
- “dateofevent” as a Date Picker
Result:
You should now see a CPT called “meetupevent” in the WordPress admin menu. When you add a new entry, you can add content, custom fields, and a taxonomy.
For further details, see the manuals of the two plugins used (“Custom Post Type UI” and ACF). This entire step works independently of JCI.
Note:
“Pods” and “Toolset” are two other plugins that are also well suited for creating CPTs.
Step 2: Create a new Custom Post Page as blueprint for all meetup-pages
The page title, URL, and other parameters of the pages to be generated will be defined in the JCI template.
But what about the design of these pages?
Create a page that serves as a blueprint and add placeholders for the JSON data. This can be an ordinary WordPress page or even an Elementor page.
In this example, we use: https://api.json-content-importer.com/generate-meetup-blueprint/
Only the Content of this generated page is relevant. The placeholders in the format ##…## will later be replaced by JSON data.
For the next step, we need the page ID of the blueprint page.
In this example, the page ID is 5130.
Step 3: Create a JCI Template that uses API data to create Custom Post Pages, Custom Post Fields (CPF), and taxonomy entries
The API data used in this example is: https://api.json-content-importer.com/extra/json/meetup/create-cpt.json, a list of several events.
This endpoint returns a list of several events.
Create a new JCI-template:
URL: See above
Name of template: “generate-meetupevent”
twig-template:
{% set contentmasterpageid = 5130 %} {# pageID of blueprint-page #}
{% set masterprop = wp_get_page_properties(FALSE, contentmasterpageid) %}
{# masterprop: {{ masterprop.get_post.ID }} #}
{% set mastercontent = masterprop.get_post.post_content %}
{#mastercontent: {{mastercontent}} <hr> #}
{#################}
{# basic settings - set CustomPostType #}
{% set cpt_slug = 'meetupevent' %} {# slug of CPT #}
{% set cpt_slug = 'events' %} {# slug of CPT #}
{# each CustomPostPage (CPP) createad out of the CustomPostType (CPT) gets a CustomPostField (CPF) with a key:value pair this pair that identifies all CPP created by this script #}
{% set cpt_cpfkey = "cptidentifier" %}
{% set cpt_cpfval = "meetupevent-uniqueidentifierforallpages" %}
{#################}
{# basic settings - CPP #}
{% set debug = FALSE %}
{% set publishdate = ("now" | date("d.m.Y")) %} {# mind the us- (month-day-year) and eu- (day-month-year) date-formatting #}
{% set postStatusUsed = "publish" %} {# publish, future, draft, pending, private #}
{% set authorid = "" %}
{% set taxonomySlug = "meeetupeventtax" %}
{#################}
{# optional: delete all previous created pages - if needed #}
{% if FALSE %}
{% set delret = wp_delete_cp_by_cpf_keyvalue(cpt_slug, cpt_cpfkey, cpt_cpfval) %}
{# delete: {{delret| dump}}<hr> #}
{% endif %}
{#################}
{# we need to build a list of all pageIDs which are created with the current JSON. later we also get a list of pageIDs created with previous JSON. If there is a pageID, which is not in the current JSON we delete it #}
{% set list_of_pageIDs_out_of_json = [] %}
{#################}
{# loop data from the API #}
{% for f in _context %}
{% if f.name %} {# check if the JSON-item is one to create a CPP #}
{# set basic fields for the CPP #}
{% set title = ""~f.name ~ ' ' ~(f.local_date | date("d.m.Y") ) %}
{% set pageslug = title ~ ' ' ~ f.local_date %}
{% set content = mastercontent %}
{% set content = ( content | preg_replace("/##description##/i", "description-title:" ~ title)) %}
{% set content = ( content | preg_replace("/##date##/i", "description-date:" ~ f.local_date)) %}
{% set content = ( content | preg_replace("/##venue##/i", "description-venue:" ~ f.venue.id)) %}
{% set excerpt = "this is excerpt, pageslug: " ~ pageslug %}
{# set CPF for the CPP #}
{% set cpf_nameofevent = f.name %}
{% set cpf_id = f.id %}
{% set cpf_statusofevent = f.status %}
{% set cpf_venueofevent = f.venue.id %}
{% set cpf_dateofevent = f.local_date %} {# mind the us- (month-day-year) and eu- (day-month-year) date-formatting #}
{# set taxonomy-field for the CPP #}
{% set taxonomyValue = 'tax-' ~ cpf_id %}
{# set updatehash-field:
if any of the JSON-data of updatehash changes, the md5-hash changes. this hash is also added to the CPP: in case of update we check if an update is really needed or not. #}
{% set updatehash = (( ("now" | date("d.m.Y H:i:s") ) ~ f.name ~ f.local_date ~ content ~ cpf_statusofevent ~ cpf_dateofevent) | md5) %} {# "now" inserts the current tie, hence updatehash changes everytime, therefore always update - to test without that: remove that item #}
{# each data-items has to have an unique id as identifier: each CPP also has a key:value pair with this id with that we can check, if a data-item already has it's CPP (then update the CPP, othereise create a CPP) #}
{# updatehash: {{updatehash}}<br>#}
{# set list of CPF key:values #}
{% set cpf_list = {
'nameofevent' : cpf_nameofevent,
'statusofevent' : cpf_statusofevent,
'dateofevent' : cpf_dateofevent,
'venueofevent' : cpf_venueofevent,
'eventid' : cpf_id,
(cpt_cpfkey) : cpt_cpfval,
} %}{# ( and ) are importaint! cpt_cpfkey:cpt_cpfval and cpf_id are unique #}
{#{% for cpfk, cpfv in cpf_list %} {{ cpfk }} -- {{ cpfv }} <br> {% endfor %}#}
{# create or update the cPP #}
{% set update_with_cpf = wp_update_cp_with_cpf(cpt_slug, title, pageslug, content, excerpt, publishdate, postStatusUsed, authorid, cpf_list, "eventid", cpf_id, "updatehash", updatehash, debug) %}
{# create / update: {{ update_with_cpf | json_encode() }}<br>#}
{# get pageID of CPP #}
{% set pageid = update_with_cpf.result.pgid %}
{# add pageID to list of valid CPP #}
{% set list_of_pageIDs_out_of_json = list_of_pageIDs_out_of_json | merge(([pageid])) %}
{# optional: delete previous added taxonomies #}
{# {% set cleartax = wp_clear_taxonomy(taxonomySlug) %} #}
{# add taxonomy #}
{#taxonomyValue: {{taxonomyValue}}, taxonomySlug: {{taxonomySlug}}<br> #}
{% set inserttax = wp_insert_taxonomy(pageid, taxonomySlug, taxonomyValue) %}
{# get taxonomies #}
{# {% set taxonomyArray = wp_get_taxonomy(pageid, taxonomySlug) %} #}
{# taxonomyArray {{pageid}}: {{taxonomyArray | dump}}<br>#}
{# {{update_with_cpf | json_encode() }}<hr>#}
{# update_with_cpf: {{ update_with_cpf | json_encode() }} <hr>#}
{{ wp_showresult_of_update_cp_with_cpf(pageid, update_with_cpf, FALSE, " / ") }}
{% endif %}
{% endfor %}
{% if _context.nojsonvalue %}
{# nojsonvalue: invalid API-data, e. g. no JSON: do not delete current pages #}
invalid data: nothing changed
{% else %}
{# list_of_pageIDs_out_of_json: {{ list_of_pageIDs_out_of_json | json_encode() }}#}
{#<hr>CLEANUP: list_of_pageIDs_out_of_json is the list of pageIDs of CPP connected to API-data.
wp_cleanup_cp selects all existing CPP then deletes all not in list_of_pageIDs_out_of_json #}
{# pageIDs with API-Data: {{list_of_pageIDs_out_of_json | json_encode()}}<hr>#}
{% set cleanup_cp = wp_cleanup_cp(list_of_pageIDs_out_of_json, cpt_slug, cpt_cpfkey, cpt_cpfval) %}
{# cleanup_cp: {{cleanup_cp | json_encode()}}<hr>#}
<hr>number of deleted pages: {{cleanup_cp.total_number_of_deleted_pageIDs}}
{% endif %}
The above code is doing this:
- Load the blueprint-content
- Set the parameter for the CPT (and a unique “meetupevent-uniqueidentifierforallpages” – set that unique if you generate more than 1 pages in this way).
- Optional: delete all existing pages of that type
- Loop through JSON and create or update the pages incl. adding CPF and Taxonomy.
- Check and delete previously created pages, which are not in the current JSON any more.
- Details of the twig-functions
Remarks:
If you use a CPT created with Toolset, add “wpcf-” to the CPF slug.
Step 4: Use the JCI Template and create the Custom Post Pages
Now you can use the following shortcode on any WordPress page:
[[jsoncontentimporterpro nameoftemplate="generate-meetupevent"]]
When you run this shortcode, you should see 8 Custom Posts created under the “meetupevent” menu.
Running the shortcode again will tell you that all 8 pages already exist.
You can also automate updates by using the Plugin GetURLCron.