We have an in-house WordPress plugin that creates content using a custom-post-type. Essentially, the content created is, for all intents and purposes, identical to WordPress 'Pages'.
The idea is that we add these custom 'pages' - via our plugin - and then deploy/update them for whomever is using the plugin. We've used our plugin to create a series of these pages, but the question is how to port this custom content with the plugin.
Initially we were thinking that since our posts have a custom post-type, we can easily identify them in the DB. In fact, we use that to remove our custom content when uninstalling the plugin.
But how do we do the inverse? Ideally we'd like to update the plugin, and with it, any custom content that we've added or modified.
Originally we were thinking of just using MySQL scripts to add this custom post content, but after a bit of research, this doesn't seem like the right way to do it.
I know WordPress has a wp_insert_post() function, but I'm just not sure of how it all fits together.
Ideally, the answer would be an overview of the process for updating our custom content. For instance, should there be a function in our plugin that, upon installation, looks for a sql file and creates new posts from it?
Thanks!
If I understand this correctly and you are trying to keep content sync'ed across multiple installations via plugin updates you will need to create a unique ID for all of your content. When you do updates programatically you are updating by the post ID but each installation will have different post IDs. You could use a post meta field to give each post a unique ID specific to your plugin. You can then query the posts based on your unique meta field.
I would code the plugin so it checks to see if there is a post with your unique ID. If it is not found then you insert a new post. If it is found then you update the post.
Let's say you have created your first piece of content and it's unique id is going to be jgohil_1. Your plugin might use something like the following to check for that unique id and then update or insert depending on if it exists.
<?php
// our meta key/value pair for our unique id
$meta_key = 'jgohil_unique_id';
$meta_value = 'jgohil_1';
// set our new content
$new_content = 'The new content here';
$new_title = 'The new title here';
// check the database to see if we have created the post already by querying for our unique id
global $wpdb;
$sql = $wpdb->prepare (
"SELECT post_id
FROM $wpdb->postmeta
WHERE meta_key = %s
AND meta_value = %s",
$meta_key,
$meta_value
);
$post_id = $wpdb->get_var( $sql );
// if we got a post id then update else insert
if ( $post_id ) {
// set up the data for updating
$data = array(
'ID' => $post_id,
'post_content' => $new_content,
'post_title' => $new_title,
);
// update the post
$updated = wp_update_post( $data );
if ( is_wp_error( $updated ) ) {
// do some error handling here
}
} else {
$data = array(
'post_title' => $new_title,
'post_content' => $new_content
'post_type' => 'your_custom_post_type'
);
$post_id = wp_insert_post( $data );
// if the insert worked give the post the unique meta id
if ( ! is_wp_error( $post_id ) && $post_id !== 0 ) {
update_post_meta( $post_id, $meta_key, $meta_value );
} else {
// do some error handling here
}
}
If you need to handle multiple pieces of content at once you would want to use a loop and change the meta value each time.
Related
I've used the Advanced Custom Fields plugin to create a new Custom Field in Wordpress. My aim now is to move all Download Links from "the_content", to the newly created Custom Field "the_field('download_link')". The issue is that I have over 10,000 posts to modify. I was wondering if there is a quick way of doing this, rather than manually moving the download link for each post?
Please see the images below for an idea of what I am trying to achieve.
Before | After
One hurdle is that all content is saved in the "wp_posts" table, where the custom field content is saved in the "wp_postmeta" table.
The content saved in the "download_link" custom field, looks like this in the "wp_postmeta" table:
(8214, 2282, 'download_link', '<div class=\"source\"><img src=\"https://www.google.com/image.png\"></div>'),
(8215, 2282, '_download_link', 'field_5cffd35335ce3'),
(8220, 2280, 'download_link', '<div class=\"source\"><img src=\"https://www.google.com/image.png\"></div>'),
(8221, 2280, '_download_link', 'field_5cffd35335ce3'),
(8226, 2278, 'download_link', '<div class=\"source\"><img src=\"https://www.google.com/image.png\"></div>'),
(8227, 2278, '_download_link', 'field_5cffd35335ce3'),
Can this be done at all? Or is the only real way to achieve this is by moving the download links manually?
Thanks in advance for your help.
It can be done automatically if the format of your download link is always the same.
Backup your database
Create a php file named my-cleanup.php.
Loop over all products, grab the link from the description and move it to a post_meta.
Launch the file with WP-CLI:
wp eval-file my-cleanup.php
Sample code
// Select the posts you want
$args = array(
'post_type' => 'post',
'post_status' => 'any',
// -1 means all posts
// For debug, set this to a small number
'posts_per_page' => 3,
);
// Retrieve posts
$query = new WP_Query( $args );
$posts = $query->posts;
// Pattern to match
// [wpdm_package id='90228']
$pattern = "/(\[wpdm_package id='\d+'\])/";
// Process posts one by one
foreach ( $posts as $post ) {
echo "Processing " . $post->post_title . "\n";
$post_args['ID'] = $post->ID;
// Get the shortcode from the post content
preg_match( $pattern, $post->post_content, $matches );
// Do we have a match?
if ( count( $matches) > 0 ) {
// Retrieve shortcode
$shortcode = $matches[0];
// Convert shortcode, maybe add some HTML
$link = do_shortcode( $shortcode );
// remove shortcode from description
$post_args['post_content'] = preg_replace( $pattern, '', $post->post_content );
// Update post
wp_update_post( $post_args );
// Create the post_metas
add_post_meta( $post->ID, '_download_link', 'field_5cffd35335ce3', true );
add_post_meta( $post->ID, 'download_link', $link, true );
}
}
Notes
Backup your database
Test on a few posts to get confidence in your code. You can restore the previous revision in the editor.
Then try on 100, then 1000. You will often find small differences in the way posts are entered.
This might take hours to run on 10.000 posts, which is why you need a WP-CLI command.
Thanks for your help in advance. Here's what I'm trying to achieve:
I have a custom post type called 'Campaigns' and I have a custom taxonomy called 'Countries' that is related to the campaign custom post type. When a user adds a new country to a campaign a new campaign post is generated that is the child of the current campaign. I'm duplicating the ACF fields that are assigned to the parent campaign and replicating the values in the child post, however I've run into an issue using the ACF flexible content fields. Here'a snippet of my code that is retrieving the parent post fields and updating the newly created ACF field in the child post with that value.
$action_text = get_post_meta($parent_id, 'action_text', true);
update_field('action_text', $action_text, $post_id);
I've tried doing this with flexible content, but I know I need to loop through and find what content blocks have been created. What is the best way to go about this?
// About Fields
$about_fields = get_post_meta($parent_id, 'content');
var_dump($about_fields);
$meta_key = // How to retrieve the flexible content keys
$meta_value_of_flexible_content = get_post_meta($parent_id, $meta_key);
if($about_fields) {
}
For clarification 'content' is the flexible container name. 'text_and_image' is an example name of one of the flexible content blocks I've created.
Thanks again for any insights.
I've tried doing this with flexible content, but I know I need to loop
through and find what content blocks have been created.
You could just use the get_field() and update_field() functions to duplicate any ACF fields, including Flexible Content fields.
So for example, to clone the whole content field:
$about_fields = get_field( 'content', $parent_id );
if ( $about_fields ) {
update_field( 'content', $about_fields, $post_id );
}
// How to retrieve the flexible content keys
foreach ( $about_fields as $arr ) {
echo 'Layout: ' . $arr['acf_fc_layout']; // e.g. "Layout: text_and_image"
// The rest of items in `$arr` are the SUB-fields of that specific layout as
// identified by the `$arr['acf_fc_layout']`, which is the layout's name. So
// if you have two SUB-fields named `text1` and `image1` respectively, then
// these items are set: `$arr['text1']` and `$arr['image1']`
}
Additional Code
To clone all ACF fields:
$fields = get_fields( $parent_id );
foreach ( $fields as $name => $value ) {
update_field( $name, $value, $post_id );
}
Additional Note
I'd change this to use the get_field() function:
$action_text = get_post_meta($parent_id, 'action_text', true);
So:
$action_text = get_field('action_text', $parent_id);
I am modifying an existing plugin and I want to add a new field to the form and then have that field be submitted along with the post. The post gets submitted to wp_posts. I have read on Google that to do this one simply needs to use update_post_meta. I am trying to insert data into a new column I made in PHPMyAdmin. I named the column post_amount. The field name is amount_field. Although I'm a beginner, something about "just use update_post_meta" that I've read seems too simple to be all that I need. But I might be wrong. Maybe I'm using it wrong?
Note - this whole attempt is due to me wanting to create a new column in the wp_posts table and add data to it with each posts. Is this even the correct way to do this? I see the words "meta_key" and "meta_value" and it makes me think that this will actually end up adding data in the wp_postmeta table....or is that the intended destination?
$question_array = array(
'post_title' => $fields['title'],
'post_author' => $user_id,
'post_content' => apply_filters('ap_form_contents_filter', $fields['description']),
'post_type' => 'question',
'post_status' => $status,
'comment_status' => 'open',
);
if(isset($fields['parent_id']))
$question_array['post_parent'] = (int)$fields['parent_id'];
$question_array = apply_filters('ap_pre_insert_question', $question_array );
$post_id = wp_insert_post($question_array);
$post_amount = $fields['amount_field']; //My code
update_post_meta($post_id, 'post_amount', $post_amount); //My code
I think you made a mistake updating your post_id.
In update_post_meta($post_id, 'post_amount', $post_amount);
you don't have ID of the post or the ID you want to update.
$post_id parameter is declared to Insert Post in your above code.
$post_id = wp_insert_post($question_array); So, update post query didn't find the ID.
You need ID to update post meta. It didn't find any id so it didn't update meta_key. SORRY FOR MY ENGLISH.
Try using add_post_meta instead of update_post_meta.
See the Reference
I am using WordPress's Advanced Custom Fields 5 plugin to create a front-end form. I would like to save the post title as one of the fields on my form. For example, one of my form fields is 'name' so I would like the post title to be 'John Smith'.
Looking at the ACF documentation it gives example code (copied below) where pre_save_post can be hooked into achieve this. Hoewver, I have included this function and the title still fails to save.
Any ideas what I am doing wrong?
Here is the code:
function my_pre_save_post( $post_id )
{
// check if this is to be a new post
if( $post_id != 'new' )
{
return $post_id
}
// Create a new post
$post = array(
'post_status' => 'draft' ,
'post_title' => $_POST['fields']['field_123'] ,
'post_type' => 'post' ,
);
// insert the post
$post_id = wp_insert_post( $post );
// return the new ID
return $post_id;
}
add_filter('acf/pre_save_post' , 'my_pre_save_post', 10, 1 );
I am using exactly the same method and it works fine.
Just a note that field_123 in your example is not the user defined field name in the wp back end but its actually the field name assigned in the meta_key value in the wp_postmeta table of you db.
I use a WordPress blog and I want to show a post without adding anything to database.
What I want to say is:
I generate a post when page loads,and prepend it in homepage.
I've searched and found wp_insert_post() function but it also add to database.
How can i do this with php?
For example:
There is a post array which is generated by a query.How can I insert my post to this array before page loaded?
I want clear my idea.Here's step by step what i want.
*1)*Im generating an array like that
$arr['title] = "my title",
$arr['content'] = "my content",
*2)*WP sends a query to database and have the posts am i right? And there is an array,to show on the theme and main page?
At this point i want to add my external array(generated in step1 ) to this array(generated by WP via a query)
3) By this way i will be able to add a post without adding it to my database.
You can simply add your virtual post in one of your theme templates as raw HTML.
Alternatively, if you're feeling adventurous, you could modify the main query results and include your post inside:
add_action('loop_start', function($query){
// create the post and fill up the fields
$post = new WP_Post((object)array(
'ID' => -1,
'post_title' => 'Bla blah',
'post_content' => 'Your content',
));
// add it to the internal cache, so WP doesn't fire a database query for it
// -1 is the ID of your post
if(!wp_cache_get(-1, 'posts'))
wp_cache_set(-1, $post, 'posts');
// prepend it to the query
array_unshift($query->posts, $post);
});
The currently accepted answer causes the new post to delete the last post in the loop, because it doesn't update the post count. Here's my modified version that also includes:
Support for empty categories.
Only one place to declare the new post's ID.
Adding is_main_query() as the person who originally answered mentioned in a comment.
A setting to decide if the new post should be appended or prepended.
Hiding the post's date because otherwise you get something like 00000000. I could have used a dynamic date but it may be bad SEO to keep updating the date without updating the content.
Hiding the post's comment link because it just leads to the homepage.
A setting to control the post type. You might prefer "page" because "post" displays a general category, which I found no way to bypass. "Page" also looks more distinguished among other posts, assuming that's a good thing.
Here's the modified code:
function virtual_post($query) {
$post_type = 'page'; // default is post
if (get_class($query)=='WP')
$query = $GLOBALS['wp_query'];
if ($query->is_main_query()) {
$append = true; // or prepend
// create the post and fill up the fields
$post = new WP_Post((object)array(
'ID' => -1,
'post_title' => 'Dummy post',
'post_content' => 'This is a fake virtual post.',
'post_date' => '',
'comment_status' => 'closed'
));
if ($post_type <> 'post')
$post->post_type = $post_type;
// add it to the internal cache, so WP doesn't fire a database query for it
if(!wp_cache_get($post->ID, 'posts')) {
wp_cache_set($post->ID, $post, 'posts');
if ($query->post_count==0 || $append)
$query->posts[] = $post;
else
array_unshift($query->posts, $post);
$query->post_count++;
}
}
}
$virtual_post_settings = array('enable' => true, 'include_empty_categories' => true);
if ($virtual_post_settings['enable']) {
if ($virtual_post_settings['include_empty_categories'])
add_action('wp', 'virtual_post');
else
add_action('loop_start', 'virtual_post');
}