0

Is there a way to set a permalink of post using a custom field? I've tried custom fields permalink 2 and while it did change the permalink structure, it gave me 404 error.

So the next option for me is to use set_permalink_structure. I need help figuring this out as I know it's not setup properly to work.

This is my code so far:

function updateNumbers() {
global $wpdb;
global $wp_rewrite;
$querystr = "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' ";
$pageposts = $wpdb->get_results($querystr, OBJECT);
$counts = 0 ;
if ($pageposts):
foreach ($pageposts as $post):
$counts++;
add_post_meta($post->ID, 'incr_number', $counts, true);
update_post_meta($post->ID, 'incr_number', $counts);
$wp_rewrite->set_permalink_structure( 'incr_number' );
endforeach;
endif;
}  
add_action ( 'publish_post', 'updateNumbers', 11 );
add_action ( 'deleted_post', 'updateNumbers' );
add_action ( 'edit_post', 'updateNumbers' );

What the code above does is assign a number in custom field called 'incr_number'. So for example, if I'm writing a post and it's the 12th post, it will assign 12 in incr_number.

I'm trying to find a way to assign that number in the permalink structure automatically without adding it manually.

UPDATE: I've found wp_update_post to update the slug but it's not working. (bold are the new changes)

function updateNumbers() {
global $wpdb;
$querystr = "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' ";
$pageposts = $wpdb->get_results($querystr, OBJECT);
$counts = 0 ;
if ($pageposts):
foreach ($pageposts as $post):
$counts++;
add_post_meta($post->ID, 'incr_number', $counts, true);
update_post_meta($post->ID, 'incr_number', $counts);
<b>wp_update_post(array('ID' => $post_id,'post_name' => get_post_meta($post_id,'incr_number', true)));</b>
endforeach;
endif;
}  
<b>add_action('save_post', 'set_slug');</b>
add_action ( 'publish_post', 'updateNumbers', 11 );
add_action ( 'deleted_post', 'updateNumbers' );
add_action ( 'edit_post', 'updateNumbers' );`

UPDATE 2: I tried to rework this but it saves the slug of the post as the custom field-2. So for example, if the custom field is 1, the slug of the post will be domain.com/1-2. And it does it for all posts. 2-2, 3-2

function updateNumbers( $post_id ){
if ( ! wp_is_post_revision( $post_id ) ){

    global $wpdb;

    $querystr = "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' ";
    $pageposts = $wpdb->get_results($querystr, OBJECT);
    $counts = 0 ;

    if ($pageposts):
        foreach ($pageposts as $post):
            $counts++;
            add_post_meta($post->ID, 'incr_number', $counts, true);
            update_post_meta($post->ID, 'incr_number', $counts);

            // unhook this function so it doesn't loop infinitely
            remove_action('save_post', 'updateNumbers');
            // update the post, which calls save_post again
            wp_update_post(array('ID' => $post_id,'post_name' => get_post_meta($post_id,'incr_number', true)));
            // re-hook this function
            add_action('save_post', 'updateNumbers');

        endforeach;
    endif;
}
}
add_action('save_post', 'updateNumbers');
  • 1
    set_permalink_structure is global to all posts, individual posts don't have permalink structures, they just have slugs. – Milo Sep 15 '17 at 5:19
  • 1
    your code is a true mess. I fail to understand what is that you are trying to do, but it is unlikely that hooking on every possible hook will get you what you want. – Mark Kaplun Sep 17 '17 at 6:04
  • 2
    The concerns I have here is that this does not scale well (fetching and updating all published posts and it's meta), possible infinite loop (saving each post, where each update, fetches and updates all posts and so on and so on recursively ...with exponential growth) and fragile permalink structure: if e.g. post with ID = 1 is deleted, then the slugs of all other posts are changed. – birgire Sep 17 '17 at 8:42
-1

I've done some research, asked on another forum and I was able to get a working solution. What the function does is it counts the posts, assigns a number to a custom field and sets the permalink structure. This is all in my theme's 'functions.php' file.

// opens the function
function updateNumbers( $post_id ){

//* Checks if the post is new or updated, if post is being updated then it skips
if ( ! wp_is_post_revision( $post_id ) ){

// global wordpress database parameters and only counts posts that are published and in the 'post' CPT
global $wpdb;
$querystr = "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE
$wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' ";
$pageposts = $wpdb->get_results($querystr, OBJECT);

// sets the counter at zero
$counts = 0 ;

// starts the loop, gets and counts how many posts are published
if ($pageposts):
foreach ($pageposts as $post):
$counts++;

// sets the number in the custom field 'incr_number'
add_post_meta($post->ID, 'incr_number', $counts, true);
update_post_meta($post->ID, 'incr_number', $counts);

// unhook this function so it doesn't loop infinitely
remove_action('save_post', 'updateNumbers');

// update the post using the custom field in the slug, which calls save_post again
wp_update_post(array('ID' => $post->ID,'post_name' => get_post_meta($post->ID,'incr_number', true)));

// re-hook this function
add_action('save_post', 'updateNumbers');

// close the loop
endforeach;
endif;

// close the function and the 'if' post is an update
}}

// hooks into the save_post process
add_action('save_post', 'updateNumbers');

// opens another call to action
add_action( 'init', function() {

// sets the global parameters for rewrite
global $wp_rewrite;

// set the permalink structure. In this example, all posts saved will be /episode/number in custom field
$wp_rewrite->set_permalink_structure( '/episode/%postname%/' );

// close the action
} );

Thanks all for the help.

Update: Here's another take:

function updateNumbers( $data, $postarr ) {
if ( !empty( $postarr['ID'] ) && ! wp_is_post_revision( $postarr['ID'] ) ) {
    if ( !( $counts = get_post_meta( $postarr['ID'], 'incr_number', true ) ) ) {
        global $wpdb;
        $counts = (int)$wpdb->get_var( "SELECT MAX(meta_value) FROM {$wpdb->postmeta} WHERE meta_key='incr_number'" );
        $counts++;
        update_post_meta( $postarr['ID'], 'incr_number', $counts );
    }
    $data['post_name'] = $counts;
}
return $data;
}
add_filter('wp_insert_post_data', 'updateNumbers', 10, 2 );
  • this will break all incoming links every time you delete a post :( will probably bring down your DB as well when you save posts – Mark Kaplun Sep 20 '17 at 3:47
  • Running it internally and have not had any problems and posts aren't going to be deleted. Granted right now it's only for five posts but what do you recommend. @MarkKaplun – Gregory Schultz Sep 20 '17 at 6:13
  • Why don't you just get the most recent post permalink in the category. Regex or explode the number off the end, add one and use it that way, only when first saved? Then you keep the permanent structure if one is deleted. – Bysander Sep 20 '17 at 12:55
  • @Bysander Can you provide an example? (The points are still available) – Gregory Schultz Sep 20 '17 at 19:39
  • 1
    Hi @GregorySchultz - I will try - in the meantime you can use this post on new vs old posts - this will help you avoid running on every save. Query your posts using something like this and you look like you pretty much have the rest. Sorry I feel that to write it all out for a reputation question would mean testing and explaining every step where I don't have time right now. I may be able to write something properly this evening. – Bysander Sep 21 '17 at 11:09
-2

You need to flush rewrite rules by adding:

// after wp_update_post()
flush_rewrite_rules( );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.