At this time I have 2 custom post-type item, projects, made custom field for attach project post in item post (custom field save post_id)
I want use attached project post-name in link:
Current link structure:
domain / {item-post-type-slug} / {item-name}
I want change to:
domain / {project->post_name} / {item-name}
With current code should flush rewrite rules on every save/delete action on projects post-type?
How to redirect old link structure to the new ?
add_action( 'init', 'add_rewrite_rules' );
function add_rewrite_rules() {
$arg = array(
'post_type' => 'projects',
'no_conflict' => '1',
'posts_per_page' => '-1'
);
$projects= new WP_Query($arg);
while($projects->have_posts() ) : $projects->the_post();
global $post;
add_rewrite_rule( $post->post_name.'/([^/]+)/?$', 'index.php?item=$matches[1]', 'top');
endwhile;
}
add_filter( 'post_type_link', 'custom_permalinks', 10, 2 );
function custom_permalinks( $permalink, $post ) {
if ( $post->post_type !== 'item' )
return $permalink;
$project_id = get_field('project', $post->ID);
$project = get_post($project_id);
$new_permalink = str_replace("item", $project->post_name, $permalink);
return $new_permalink;
}
For flush rewrite rules using
function flush_project_links( $post_id) {
if ( get_post_type( $post_id ) != 'projects' )
return;
flush_rewrite_rules();
}
add_action('delete_post', 'flush_project_links', 99, 2);
add_action('save_post', 'flush_project_links', 99, 2);
but it's work only on second time when update post
UPDATED:
flush rewrite fixed:
function flush_project_links( $post_id) {
if ( get_post_type( $post_id ) != 'projects' )
return;
add_rewrite_rules()
flush_rewrite_rules();
}
add_action('delete_post', 'flush_project_links', 99, 2);
add_action('save_post', 'flush_project_links', 99, 2);
and removed add_action( 'init', 'add_rewrite_rules' );
Related
I created a custom post type with a plugin. A registered user can insert a new post from front-end and it is saved as draft. When I edit it in back-end I need it is saved with private visibility.
I found this snippet to set visibility by default:
public function force_dpa_request_private( $data , $postarr ) {
if( empty( $data['post_name'] ) && 'my-cpt' == $postarr['post_type'] )
$data[ 'post_status' ] = 'private';
return $data;
}
but it works only on first insert, when I edit it the visibility change to public...
You can hook to the save_post which is called after the post is created or updated.
<?php
add_action( 'save_post', 'callback_save_post', 10, 3);
function callback_save_post( $post_ID, $post, $update ){
if ( 'my-cpt' === get_post_type( $post_ID) && ! wp_is_post_revision( $post_ID ) ) {
// unhook this function so it doesn't loop infinitely
remove_action('save_post', 'callback_save_post', 10 );
// Make the post private if it is edited else make it draft.
if ( $update ) {
$postarr = array(
'ID' => $post_ID,
'post_status' => 'private'
);
} else {
$postarr = array(
'ID' => $post_ID,
'post_status' => 'draft'
);
}
// Update the post.
wp_update_post( $postarr );
// re-hook this function.
add_action( 'save_post', 'callback_save_post', 10, 3);
}
}
Reference:
https://developer.wordpress.org/reference/hooks/save_post/
https://codex.wordpress.org/Function_Reference/wp_update_post
Slight variation from your question, but you can still edit the post on creation, if you make all your post type private. Thus this works.
function force_type_private($post)
{
if ($post['post_type'] == 'Your Post Type')
$post['post_status'] = 'private';
return $post;
}
add_filter('wp_insert_post_data', 'force_type_private');
I'm attempting to get the ID of the post I am editing in functions.php for the purpose of dynamically rewriting a custom post type slug.
This is what I'm working with so far.
function change_post_type_slug( $args, $post_type ) {
if ( 'custom_post' == $post_type ) {
global $post;
$location = get_field('custom_field', $post->ID);
$args['rewrite']['slug'] = $location;
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_type_slug', 10, 2 );
I am not sure if the hook register_post_type_args is firing before I am able to get the ID, or if this is even the best way to go about what I am trying to accomplish. Can't find much out there on the subject.
I was able to get it to work with the following:
function change_post_type_slug( $args, $post_type ) {
if ( 'lead_page' == $post_type ) {
$post_id = $_GET['post'];
$location = get_field('leadpage_location', $post_id);
$args['rewrite']['slug'] = $location->post_name;
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_type_slug', 10, 2 );
However it resulted in a notice on the front-end:
Notice: Undefined index: post in /path/to/wordpress/functions.php on line 623
Line 623 is $post_id = $_GET['post'];
You should use the updated_postmeta hook for this, as its run every time you update your custom fields.
Then you can update your post data with wp_update_post() function.
add_action( 'updated_postmeta', function( $meta_id, $object_id, $meta_key, $meta_value ) {
if ( 'location' === $meta_key ) {
wp_update_post([
'ID' => $object_id,
'post_name' => $meta_value,
]);
}
}, 10, 4 );
Update:
Try this:
function change_post_types_slug( $args, $post_type ) {
if ( 'your-custom_post' === $post_type ) {
// Check and get the custom post ID
$id = isset($_GET[ 'post' ]) ? $_GET[ 'post' ] : '' ;
// $location = get_field('leadpage_location', $id);
$args['rewrite']['slug'] = 'new-slug-here';
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_types_slug', 10, 2 );
Try this out:
function change_post_type_slug( $args, $post_type ) {
if ( 'lead_page' === $post_type && is_admin() && $_GET['action'] === 'edit' ) {
$post_id = $_GET['post'];
$location = get_field('leadpage_location', $post_id);
$args['rewrite']['slug'] = $location->post_name;
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_type_slug', 10, 2 );
It adds two more conditionals, to check if you're on the admin screen and to check of there is a GET parameter of edit. Probably overkill to do is_admin() as well, but now you're super safe.
I have a custom post type named location and I'm trying to set posts of this type as children of existing pages, to achieve a permalink structure like this:
example.com/alabama <-- Page with generic content
example.com/alabama/locations <-- Another page, child of a state page
example.com/alabama/locations/location-name <- Custom type, child of alabama/locations seen above and titled `Location Name`
The closest I've got to create hierarchical relationships between two distinct post types was through a meta box where I can assign a post ID as the post_parent of my custom type posts when saving them. However despite the page ID being indeed saved to the CPT post_parent field, it has no effect on the permalinks. They are coming as defined in the rewrite CPT option. But I don't know how to make the ['rewrite']['slug'] option dynamic, or if it's even possible.
This is how my post type is being defined:
add_action( 'init', function() {
register_post_type( 'location', [
'label' => 'Location',
'menu_icon' => 'dashicons-location-alt',
'supports' => [ 'title', 'editor', 'custom-fields' ],
'public' => true,
'hierarchical' => false,
'has_archive' => false,
'rewrite' => false,
] );
} );
How can I configure the rewrite rules for locations to get the permalinks I need?
I'm assuming that all the location posts will have a permalink structure that looks like this:
example.com/{STATE NAME}/locations/{CPT SLUG}
Sample URL addresses:
http://example.com/alabama/locations/location-1
http://example.com/alabama/locations/location-2
http://example.com/new-york/locations/location-3
So if that is correct, then:
• Use the add_rewrite_rule() function to add a custom rewrite rule for those permalinks.
• You don't need the /locations/ Page.
add_action( 'init', function(){
// Handles requests to `your-site-domain.com/{STATE NAME}/locations/{CPT SLUG}`
add_rewrite_rule(
'([^/]+)/locations/([^/]+)(?:/([0-9]+))?/?$',
'index.php?location=$matches[2]&page=$matches[3]&state_name=$matches[1]',
'top'
);
// Allows you to retrieve the `state_name`; for example using `get_query_var()`.
add_rewrite_tag( '%state_name%', '([\w\-]+)' );
} );
(You can change state_name to another name; it's up to you. And don't forget to flush the rewrite rules — go to the Permalink Settings page and click on the Save Changes button without having to make any changes.)
Next, when you create or edit a location post, set the value of the post_parent custom field to the ID of the 'state Page' — e.g. the /alabama/ Page.
And this code will filter the get_permalink() output, and returns the appropriate permalink for a location post:
add_filter( 'post_type_link', 'so51217355_post_type_link', 10, 2 );
function so51217355_post_type_link( $permalink, $post ) {
if ( 'location' === $post->post_type ) {
$page_id = get_post_meta( $post->ID, 'post_parent', true );
$state_name = ( is_numeric( $page_id ) && $page_id ) ?
get_post_field( 'post_name', $page_id ) : null;
// Make sure the post is associated to a valid 'state Page'.
if ( $state_name ) {
$permalink = $state_name . '/locations/' . $post->post_name;
$permalink = home_url( user_trailingslashit( $permalink ) );
}
}
return $permalink;
}
So for example, get_permalink( 123 ) would return http://example.com/alabama/locations/location-1, if the location post's slug is location-1, and its 'state Page' is /alabama/.
UPDATE
When the permalink is requested (i.e. users visit example.com/{STATE NAME}/locations/{CPT SLUG}), and you want to make sure the 'state Page' and location post both exist, and that the 'state Page' was indeed associated to the location post, then this code can help you:
// Validates the `state_name` of the current page/URL.
add_action( 'parse_request', 'so51217355_parse_request' );
function so51217355_parse_request( $wp ) {
if ( ! empty( $wp->query_vars['state_name'] ) &&
! empty( $wp->query_vars['location'] ) ) {
global $wpdb;
$page_id = $wpdb->get_var( $wpdb->prepare(
"SELECT ID FROM {$wpdb->posts} WHERE post_name = %s",
$wp->query_vars['state_name']
) );
if ( ! is_numeric( $page_id ) || ! $page_id ) {
$wp->query_vars['error'] = '404';
// Don't let WordPress finds a post with nearest match.
remove_action( 'template_redirect', 'redirect_canonical' );
return;
}
$post_id = $wpdb->get_var( $wpdb->prepare(
"SELECT ID FROM {$wpdb->posts} WHERE post_name = %s",
$wp->query_vars['location']
) );
$page_id2 = get_post_meta( $post_id, 'post_parent', true );
if ( (int) $page_id2 !== (int) $page_id ) {
$wp->query_vars['error'] = '404';
// Don't let WordPress finds a post with nearest match.
remove_action( 'template_redirect', 'redirect_canonical' );
}
}
}
UPDATE #2
Refer to the // Comment in the code below this image — see the _so51217355_admin_ajax_js() function.
add_action( 'wp_ajax_so51217355_admin_ajax', '_so51217355_admin_ajax_php' );
function _so51217355_admin_ajax_php() {
$post_id = filter_input( INPUT_POST, 'post_id' );
echo get_sample_permalink_html( $post_id );
wp_die();
}
add_action( 'admin_print_footer_scripts', '_so51217355_admin_ajax_js', 11 );
function _so51217355_admin_ajax_js() {
$screen = get_current_screen();
if ( 'location' === $screen->id ) :
?>
<script>
// This script will sync the Permalink under the big/main post title box on
// the Edit Post page; but only if and when editing or deleting the custom
// field as in `meta_key` below. Make sure to change it, if necessary.
jQuery( function( $ ){
var meta_key = 'post_parent';
function ajax() {
$.post( ajaxurl, {
action: 'so51217355_admin_ajax',
post_id: $( '#post_ID' ).val()
}, function( s ){
$( '#edit-slug-box' ).html( s );
} );
}
function _go( e, a ) {
var $input = $( a.target ),
mid, mkey;
if ( /^meta\-(\d+)\-submit$/.test( $input.attr( 'name' ) ) ||
/^deletemeta\[(\d+)\]$/.test( $input.attr( 'name' ) ) ) {
mid = RegExp.$1;
mkey = $( 'input[name="meta[' + mid + '][key]"]' ).val();
if ( meta_key === mkey ) {
ajax();
}
}
}
$( '#the-list' )
.on( 'wpListAddEnd', _go )
.on( 'wpListDelEnd', _go );
} );
</script>
<?php
endif;
}
I am making my custom permalinks and want to get the post author id in it I have tried many things but all in vain, Please help me on this one.
STEP 1 add this into your functions.php
Guidance here
https://wordpress.stackexchange.com/questions/112719/how-to-use-author-id-in-post-permalink
function wpse_112719_pre_post_link( $permalink, $post, $leavename ) {
if ( strpos( $permalink, '%author%' ) !== false ) {
$authordata = get_userdata( $post->post_author );
$author_id = $authordata->ID;
$permalink = str_replace( '%author%', $author_id, $permalink );
}
return $permalink;
}
add_filter( 'pre_post_link', 'wpse_112719_pre_post_link', 10, 3 );
function wpse_112730_add_rewrite_rules() {
add_rewrite_rule(
"([0-9]+)/(.*)",
'index.php?name=$matches[2]',
'top'
);
}
add_action( 'init', 'wpse_112730_add_rewrite_rules' );
STEP 2 login to admin end and set the permalinks Custom Structure some thing like this : /%postname%/%author%
I want to use something like:
http://example.com/%category_id%/%postname%/
for the permalink structure.
For example, if a post has a category with an ID of 3, then the URL for the post will be
http://example.com/3/post-name/
Does anyone know how this can be done? I don't mind modifying WordPress core.
This code adds the %category_id% rewrite tag, and filters post permalinks to replace them with the actual category ID (lowest if there are multiple categories). You can place this in a plugin or in your theme file.
add_action( 'init', 'so6159452_init' );
function so6159452_init()
{
add_rewrite_tag( '%category_id%', '([0-9]+)' );
}
add_filter( 'post_link', 'so6159452_post_link', 10, 2 );
function so6159452_post_link( $permalink, $post )
{
if ( false !== strpos( $permalink, '%category_id%' ) ) {
$cats = get_the_category( $post->ID );
if ( $cats ) {
usort( $cats, '_usort_terms_by_ID' ); // order by ID
$category_id = $cats[0]->cat_ID;
} else {
// Error: no category assigned to this post
// Just use a dummy variable
$category_id = '0';
}
$permalink = str_replace( '%category_id%', $category_id, $permalink );
}
return $permalink;
}