I'm wanting to change a WordPress post's permalink (post_name) dynamically every time time a post is saved/updated by pulling from a custom field present in the post and replacing the permalink with this value. I have code within functions.php which is working, except that it appends -2 to the permalink. I assume this is because something is occurring twice, the first time resulting in the permalink I want, and the second resulting in WordPress responding to the "duplicate" by adding -2.
This is the current code:
add_action('save_post', 'change_default_slug');
function change_default_slug($post_id) {
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
return;
if ( !current_user_can('edit_post', $post_id) )
return;
remove_action('save_post', 'change_default_slug');
wp_update_post(array('ID' => $post_id, 'post_name' =>get_post_meta($post_id,'request_number',true)));;
add_action('save_post', 'change_default_slug');
}
I'll take a crack at this...
Now, this is assuming that you are using ACF for your custom field...
If not, simply update the code with the WP custom meta functions instead. Oh, don't forget the change the field_5fed2cdbc1fd2 with your ACF field Key
add_filter('save_post', 'change_post_name', 20, 1);
function change_post_name($post_id)
{
$post_type = get_post_type();
if ($post_type == "post"){
$acf_title_field = $_POST['acf']['field_5fed2cdbc1fd2']; // get the field data by $_POST
if (!empty($acf_title_field)) {
// update the title in database
$wpdb->update($wpdb->posts, array('post_title' => $acf_title_field, 'post_name' => sanitize_title($acf_title_field)), array('ID' => $post_id));
}
}
}
add_filter( 'wp_insert_post_data', 'update_post_name', 50, 2 );
function update_post_name( $data, $postarr ) {
$post_type = get_post_type();
if ($post_type == "post"){
//Check for the post statuses you want to avoid
if ( !in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
$acf_title_field = $_POST['acf']['field_5fed2cdbc1fd2']; // get the field data by $_POST
// $data['post_name'] = sanitize_title( $data['post_title'] );
$data['post_name'] = sanitize_title( $acf_title_field );
}
return $data;
}
}
Related
I am currently trying to use the first image of an ACF gallery field as featured image.
The plugin I use is called Frontend Admin, it allows users to create posts from the frontend.
While my script works in the WordPress backend, it does not work for the frontend submission:
add_action('acf/save_post', 'first_Image_featured', 50);
function first_Image_featured() {
//get important fields
$current_screen = get_current_screen(); // Current admin screen needed to identify the current cpt
$current_cpt_name = 'musterkueche'; // Current CPT name
$current_cpt_support = 'thumbnail'; // Check if the CPT supports this feature
global $post;
$post_id = ( $post->ID ); // Current post ID
$post_gallery_field = get_field('musterkuchengalerie', $post_id ); // ACF Image Gallery field
if ( !empty( $post_id ) ) {
if ( isset( $post_gallery_field['0'] ) ) {
$post_image_id = $post_gallery_field['0']['id']; // ACF image filed ID
$post_image_url = $post_gallery_field['0']['url']; // ACF image filed URL
// If current CPT supports thumbnails/featured images
if ( post_type_supports( $current_cpt_name, $current_cpt_support ) ) {
if ( ( $post_image_url ) AND ( ( $post_image_url ) != ( get_the_post_thumbnail() ) ) ) {
update_post_meta($post_id, '_thumbnail_id', $post_image_id);
}
}
} else {
update_post_meta( $post_id, '_thumbnail_id', 0 );
}
}
}
The Plugin Developer of Frontend Admin said:
Our frontend forms don't fire the acf/save_post hook, use do_action( 'frontend_admin/save_post', $form, $post_id ); instead.
$form (array) The form settings, including $form['record']['post'] which contains all of the submitted post fields’ data.
$post_id (int|string) The ID of the post being edited.
acf/save_post comparison for Frontend Admin
This hook is a bit different from acf/save_post so be aware of these differences:
$post_id is the second of two parameters, so make sure to include
both parameters and to set the fourth argument of add_action to “2”.
This hook is always fired after the fields have been saved so none of
the fields will be in the $_POST global but rather within the
$form['record']['fields'][‘post'] array.
Example Function for Frontend Admin (For sending email after post is saved)
add_action('frontend_admin/save_post', 'my_frontend_save_post', 10, 2);
function my_frontend_save_post( $form, $post_id ) {
//get important fields
$post_content = get_post_field('post_content',$post_id);
$post_title = get_post_field('post_title',$post_id);
$email_address = get_field('email_address', $post_id);
if( $email_address ) {
$email_sent = wp_mail( $email_address, $post_title, $post_content );
}
}
My second approach (dosent work):
add_action('frontend_admin/save_post', 'first_Image_featured', 10, 2);
function first_Image_featured ($form, $post_id) {
//get important fields
$current_screen = get_current_screen(); // Current admin screen needed to identify the current cpt
$current_cpt_name = get_post_type('musterkueche'); // Current cpt name
$current_cpt_support = 'thumbnail'; // Check if the CPT supports this feature
global $post; // This needs to be changed, but I dont understand the Documentation
$post_id = ( $post->ID ); // Current post ID
$post_gallery_field = get_field('musterkuchengalerie', $post_id); // ACF Image Gallery field
if ( !empty( $post_id ) ) {
if ( isset( $post_gallery_field['0'] ) ) {
$post_image_id = $post_gallery_field['0']['id']; // ACF image filed ID
$post_image_url = $post_gallery_field['0']['url']; // ACF image filed URL
// If current cpt supports thumbnails/featured images
if ( post_type_supports( $current_cpt_name, $current_cpt_support ) ) {
if ( ( $post_image_url ) AND ( ( $post_image_url ) != ( get_the_post_thumbnail() ) ) ) {
update_post_meta($post_id, '_thumbnail_id', $post_image_id);
}
}
} else {
update_post_meta( $post_id, '_thumbnail_id', 0 );
}
}
}
I need some help with a woocommerce website with a function.php file that I edit within a plugin called WP All Import. It's linked to a plugin that imports csv & xml files.
In WP All Import I set the import title as [product_title({product_name[1]}, {size[1]}, {colour[1]})] and it picks up the items from an import.
What I'm trying to do is set the product name as a combination of variables. So in the example below, if both $size and $colour are empty I want the product name to just be $name. If $size is empty, then $name - $colour. If $ colour is empty then $name - $size. And then if they all have values $name - $colour - $size.
function product_title($name, $size, $colour)
{
$newName = $name;
if (strpos($size, "")) {
if (strpos($colour, ""))
{
$newName = "$name";
}
}
else if (strpos($size, ""))
{
$newName = "$name - $colour";
}
else if (strpos($colour, ""))
{
$newName = "$name - $size";
}
else
{
$newName = "$name - $colour - $size";
}
}
At the moment this is leaving the titles as blank. Where did I go wrong?
I've had to do this not so long ago. It's pretty tricky to understand. In short you can't use pre_get_post because the terms are not set yet. You must use save_post with wp_update_post, but there is a few thing to understand like the infinite loop case.
Don't hesitate to adapt it. I guessed that colors and sizes are custom taxonomies, just make sure the slugs matches. Modify it and have fun.
<?php
add_action( 'save_post', 'worker', 10, 3 );
function worker( $post_id, $post, $update ) {
// ... if not the admin side or if user can't edit post, then bail
if ( ! is_admin() || ! current_user_can( 'edit_post', $post_id ) )
return;
$worker = ( object ) [
'post_type' => 'product', // ... set our taxonomy in your case, "product"
'taxonomies' => [ 'colour', 'size', ], // ... set the taxonomies that we want to use in our title
];
// ... if not a post.php page or post-new.php page, then bail
$base = [
'post.php',
'post-new.php',
];
if( ! in_array( filter_input( INPUT_SERVER, 'REQUEST_URI' ), $base, true ) && $post->post_type != $worker->post_type )
return;
// ... do not update title if autosave
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
// ... fetch our terms and join them
$terms = join( ' - ', wp_list_pluck( wp_get_object_terms( $post_id, $worker->taxonomies ), 'name' ) );
// ... define our title structure
$self = $post->post_title . $terms . '#' . $post_id; // ... You should leave the post_id as a unique identifer, so you don't end up with 2 product with the same title
// ... https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops
remove_action( 'save_post', 'worker' );
wp_update_post( array(
'ID' => $post_id,
'post_title' => esc_attr( $self ),
'post_name' => sanitize_title( $self ),
) );
add_action( 'save_post', 'worker', 10, 3 );
}; ?>
I've read other answers about assigning category based on post tags. But can this be done based on postmeta?
I'm assuming it can be and I've been trying to change the following snippet (quoted in another answer) to achieve this. But I've had no luck tweaking it to reference postmeta meta_key (delivery_option) and meta_value (pick-up, postal, post & parcel), to then auto assign a category (pick-up, postal or post & parcel).
In case it's relevant, the above postmeta key and value have been added by another plugin.
function auto_add_category ($product_id = 0) {
if (!$product_id) return;
// because we use save_post action, let's check post type here
$post_type = get_post_type($post_id);
if ( "product" != $post_type ) return;
$tag_categories = array (
'ring' => 'Jewellery'
'necklace' => 'Jewellery',
'dress' => 'Clothing',
);
// get_terms returns ALL terms, so we have to add object_ids param to get terms to a specific product
$product_tags = get_terms( array( 'taxonomy' => 'product_tag', 'object_ids' => $product_id ) );
foreach ($product_tags as $term) {
if ($tag_categories[$term->slug] ) {
$cat = get_term_by( 'name', $tag_categories[$term->slug], 'product_cat' );
$cat_id = $cat->term_id;
if ($cat_id) {
$result = wp_set_post_terms( $product_id, $cat_id, 'product_cat', true );
}
}
}
}
add_action('save_post','auto_add_category');
Disclosure: I'm building a WordPress website and learning as I go. This may be an obvious question, but be assured that its being asked after hours of research to try and answer myself (it's all good I've learnt other stuff while researching... just not the right stuff!). HUGE thanks in advance for any mastery insights.
This code when placed in your functions.php file will check the product's delivery option and then assign the corresponding category to the product. If any product categories for that product already exist it will append them to the list. The product category would need to exist in the first place and if it does then it assigns that category with the same slug as the delivery option. I use the hook save_post_product so that it fires only on updating products.
add_action('save_post_product', 'update_product_category', 20, 3);
function update_product_category( $post_id, $post, $update ) {
$product = wc_get_product( $post_id );
$delivery_methods = array( 'pick-up', 'postal', 'post', 'parcel' );
$delivery_option = get_post_meta($post_id, 'delivery_option', true);
if( ! empty( $delivery_option ) ) {
$product_cats = $product->get_category_ids();
foreach( $delivery_methods as $delivery_method) {
if( $delivery_option === $delivery_method ) {
$pickup_cat_id = get_term_by('slug', $delivery_method, 'product_cat')->term_id;
if( $pickup_cat_id && ! in_array( $pickup_cat_id, $product_cats) ) {
$product_cats[] = $pickup_cat_id;
$product->set_category_ids($product_cats);
$product->save();
}
}
}
}
}
I have a custom post type named "Designer" Each posts will be using different unique Advanced Custom Fields as each posts has unique templates.With the below code I am able to give rules for each posts in Designer post type and save but the custom fields are not displaying on post edit pages on backend.
Normally this code should ork but no idea what happend to the code
Please Help.
add_filter('acf/location/rule_types', 'acf_location_rules_types');
function acf_location_rules_types( $choices )
{
$choices['Custom Post types']['cpt_parent'] = 'Custom post type parent';
return $choices;
}
add_filter('acf/location/rule_values/cpt_parent', 'acf_location_rules_values_cpt_parent');
function acf_location_rules_values_cpt_parent( $choices )
{
$args = array(
'hierarchical' => true,
'_builtin' => false
);
$posttypes = get_post_types( $args );
if( $posttypes )
{
foreach( $posttypes as $posttype ):
if( $posttype != 'acf' ):
$args = array(
'post_type' => 'designer',
'posts_per_page' => -1,
'post_status' => 'publish'
);
$customposts = get_posts( $args );
if ( $customposts ) {
foreach( $customposts as $custompost ){
$choices[ $custompost->ID] = $custompost->post_title;
}
}
endif;
endforeach;
}
return $choices;
}
//MATCH THE RULE
add_filter('acf/location/rule_match/cpt_parent', 'acf_location_rules_match_cpt_parent', 10, 3);
function acf_location_rules_match_cpt_parent( $match, $rule, $options )
{
global $post;
$selected_post = (int) $rule['value'];
// post parent
$post_parent = $post->post_parent;
if( $options['page_parent'] ) {
$post_parent = $options['page_parent'];
}
if ($rule['operator'] == "=="){
$match = ( $post_parent == $selected_post );
}
elseif ($rule['operator'] != "!="){
$match = ( $post_parent != $selected_post );
}
return $match;
}
Your Artist Collection field group is set to only appear on one post, the post Designer Post 1 which is a Designer Post type.
I don't understand what all the code is for? Just create a different field group for each post that needs a different field group and a separate rule for each.
Ok sorry I understand the issue now and I have recreated the issue on my local install.
On the line of code below you are looking for the post_parent but I think you should be looking for the ID.
I changed this:
$post_parent = $post->post_parent;
to this:
$post_parent = $post->ID;
and it's working for me.
If I understand your problem correctly, in wp-admin post edit page click on screen options on the upper right corner. In the menu that appears make sure the Custom fields is selected. This will make the custom fields appear for edit.
When I save the post It create one post with correct value and an other with no title and no value!
add_filter('acf/pre_save_post' , 'tsm_do_pre_save_post' );
function tsm_do_pre_save_post( $post_id ) {
// Create a new post
$post = array(
'post_type' => 'itemfounds', // Your post type ( post, page, custom post type )
'post_status' => 'draft', // (publish, draft, private, etc.)
'post_title' => 'Δωρεά σε είδος για το "'.get_the_title(wp_strip_all_tags( $_POST['acf']['field_5696694332974'] )).'"' , // Post Title ACF field key
);
// insert the post
$post_id = wp_insert_post( $post );
session_start();
$_SESSION['item_pid'] = $post_id;
// Save the fields to the post
// do_action( 'acf/save_post' , $post_id );
return $post_id;
}
You can use acf by this way:-
$post_id (array) the ID of the post being saved
BEFORE
<?php
function my_acf_save_post( $post_id ) {
// bail early if no ACF data
if( empty($_POST['acf']) ) {
return;
}
// array of field values
$fields = $_POST['acf'];
// specific field value
$field = $_POST['acf']['field_abc123'];
}
// run before ACF saves the $_POST['acf'] data
add_action('acf/save_post', 'my_acf_save_post', 1);
?>
AFTER
<?php
function my_acf_save_post( $post_id ) {
// get new value
$value = get_field('my_field');
// do something
}
// run after ACF saves the $_POST['acf'] data
add_action('acf/save_post', 'my_acf_save_post', 20);
?>
Hope this will help you :)