I have an URL like this:
example.com/movies/157336/Interstellar
For reference:
example.com/movies/%movie_id%/%movie_name%
Please note, the movie_id is a custom field, and not the actual post ID.
The movie_name is the post title slug, but is only there for SEO reasons.
I need WordPress to load the page based on the custom field movie_id found in the URL and not use the page name, and if the movie_id is not found, throw the regular 404 error.
The main problem I am having, is that I can’t seem to get WordPress to load a page based on the custom field movie_id from the URL, it always uses movie_name as reference point.
How do I know that? Well the correct URL would be example.com/movies/157336/Interstellar and if I change the title to example.com/movies/157336/Intersterlarxyz then WordPress gives a 404 error.
And if I change the ID but leave the movie name correct, like this: example.com/movies/123/Interstellar then WordPress still loads the correct page.
Based on this behavior, it's safe to say WordPress loads the page based on the page slug from the URL, rather than the movie ID, and that is what I need to fix.
Here is my code so far:
movie-plugin.php
// Register Custom Post Type "movies"
function register_moviedb_post_type() {
register_post_type( 'movies',
array(
'labels' => array(
'name' => __( 'Movies' ),
'singular_name' => __( 'Movies' )
),
'taxonomies' => array('category'),
'public' => true,
'has_archive' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'movies','with_front' => FALSE),
'supports' => array( 'title', 'editor', 'custom-fields','comments','page-attributes','trackbacks','revisions', 'thumbnail')
)
);
flush_rewrite_rules();
}
add_action( 'init', 'register_moviedb_post_type' );
// Add custom rewrite tag 'movie_id'
function custom_rewrite_tag() {
add_rewrite_tag('%movie_id%', '([^/]+)', 'movie_id=');
}
add_action('init', 'custom_rewrite_tag');
// Add rewrite rule
function custom_rewrite_basic() {
add_rewrite_rule(
'^movies/([^/]*)/([^/]*)/?',
//'index.php?post_type=movies&movie_id=$matches[1]',
'index.php?post_type=movies&movie_id=$matches[1]&name=$matches[2]',
'top'
);
}
add_action('init', 'custom_rewrite_basic');
// Query var 'movie_id'
function add_query_vars_filter( $vars ){
$vars[] = "movie_id";
return $vars;
}
add_filter( 'query_vars', 'add_query_vars_filter' );
// Custom Page Template
function custom_movie_page_template() {
if ( is_singular( 'movies' ) ) {
add_filter( 'template_include', function() {
return plugin_dir_path( __FILE__ ) . '/movies.php';
});
}
}
add_action( 'template_redirect', 'custom_movie_page_template' );
// Create custom post type link for movies
function movie_post_type_link( $link, $post = 0 ){
if ( $post->post_type == 'movies' ){
$id = $post->ID;
$post = &get_post($id);
$movie_id = get_post_meta($post->ID,'movie_id', true);
empty ( $post->slug )
and $post->slug = sanitize_title_with_dashes( $post->post_title );
return home_url(
user_trailingslashit( "movies/$movie_id/$post->slug" )
);
} else {
return $link;
}
}
add_filter( 'post_type_link', movie_post_type_link, 1, 2 );
If I remove the movie_name from the URL in add_rewrite_rule, WordPress just loads the archive page of that post type.
'index.php?post_type=movies&movie_id=$matches[1]',
If I use the page name in the URL rewrite, it always loads the page based on the name, rather than the movie_id.
'index.php?post_type=movies&movie_id=$matches[1]&name=$matches[2]',
I didn't test code below, but movies.php could be like this:
<?php $movieId = (int)get_query_var('movie_id') ;
if(movieId ==! 0):
$args = array(
'post_type' => 'movies',
'posts_per_page' => 1,
'meta_key' => 'movie_id',
'meta_value' => $movieId
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
//code that display data
<?php endwhile; else : ?>
//code to create post
<?php endif;
else:
//normal loop
endif;
Related
I am having the following issues with rendering custom permalinks using WordPress, the Advanced Custom Fields post object field and Timber. I have posts and a custom post type photo galleries that are related and are connected by a link setup using the post object field attached to the story post. The rendered links are being displayed like this: http://example.com/photos/%locations%/bordeaux/. The %locations% segment should be replaced by world/france in this example.
The permalinks are properly rendered when access using the post's permalink (http://example.com/photos/world/france/bordeaux), attached to a WordPress menu or navigated to using the core search functionality.
The post object has the following parameters set:
Filter by Post Type: Photo Gallery (custom post type)
Return Format: Post Object
I have included my custom post type, taxonomy, and post_type_link functions below.
Custom post type (abbreviated)
function gerryfeehan_register_photos_post_type() {
$args = [
'label' => 'Photo Galleries',
'labels' => [],
'supports' => array(),
'public' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-format-gallery',
'capability_type' => 'post',
'taxonomies' => [ 'locations', ],
'has_archive' => true,
'delete_with_user' => false,
'rewrite' => [
'slug' => 'photos/%locations%',
'with_front' => false,
],
];
register_post_type( 'photos', $args );
}
add_action( 'init', 'gerryfeehan_register_photos_post_type' );
Custom taxonomy (abbreviated)
function gerryfeehan_register_locations_taxonomy() {
$args = [
'labels' => [],
'hierarchical' => true,
'rewrite' => [
'slug' => 'locations',
'hierarchical' => true,
],
];
register_taxonomy( 'locations', [ 'photos' ], $args );
}
add_action( 'init', 'gerryfeehan_register_locations_taxonomy' );
Post type link filter function
add_filter( 'post_type_link', 'gerryfeehan_post_type_link', 10, 2 );
function gerryfeehan_post_type_link( $post_link ) {
$taxonomy = 'locations';
$terms = get_the_terms( get_the_ID(), $taxonomy );
$slug = [];
// Warning: Invalid argument supplied for foreach()
foreach ( $terms as $term ) {
if ( $term->parent == 0 ) {
array_unshift( $slug, sanitize_title_with_dashes( $term->name ) );
} else {
array_push( $slug, sanitize_title_with_dashes( $term->name ) );
}
}
if ( ! empty( $slug ) ) {
return str_replace( '%' . $taxonomy . '%' , join( '/', $slug ) , $post_link );
}
return $post_link;
}
Timber get_field function
{{ story.get_field( 'associated_photo_gallery' ).link }}
Any suggestions on why the permalinks are not rendering correctly when being used by Advanced Custom Fields and Timber.
As far as I can see, your configuration for your custom permalink structure in register_post_type() looks fine.
The reason why you get an "Invalid argument supplied for foreach()" warning is because the post_type_link filter runs for every post type. But the locations taxonomy probably isn’t registered for every post type of your site and the get_the_terms() function returns false if there are no terms.
To fix this you should add a bailout that returns early when it’s not the photos post type. For that, you can use the $post parameter, that is provided as the second argument in the filter.
add_filter( 'post_type_link', 'gerryfeehan_post_type_link', 10, 2 );
function gerryfeehan_post_type_link( $post_link, $post ) {
// Bail out if not photos post type.
if ( 'photos' !== $post->post_type ) {
return $post_link;
}
$taxonomy = 'locations';
$terms = get_the_terms( get_the_ID(), $taxonomy );
$slug = [];
foreach ( $terms as $term ) {
if ( $term->parent == 0 ) {
array_unshift( $slug, sanitize_title_with_dashes( $term->name ) );
} else {
array_push( $slug, sanitize_title_with_dashes( $term->name ) );
}
}
if ( ! empty( $slug ) ) {
$post_link = str_replace( '%' . $taxonomy . '%', join( '/', $slug ), $post_link );
}
return $post_link;
}
Also, you need to make sure that you flush your permalinks by visiting the Settings → Permalinks page in the WordPress admin.
Im trying to filter my custom post types by a checkbox field of ACF.
I work with this tutorial: https://www.advancedcustomfields.com/resources/creating-wp-archive-custom-field-filter/
Now I got the problem that nothing change, when ich filter over the checkboxes on the archive page of the custom post type. It generates only the right URL but doesn't filter the posts.
Does some have any idea why?
function.php:
// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array(
'mitglieder' => 'mitglieder'
);
// action
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ) return;
// bail early if not main query
// - allows custom code / plugins to continue working
if( !$query->is_main_query() ) return;
// get meta query
$meta_query = $query->get('meta_query');
// loop over filters
foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
// continue if not found in url
if( empty($_GET[ $name ]) ) {
continue;
}
// get the value for this filter
// eg: http://www.website.com/events?city=melbourne,sydney
$value = explode(',', $_GET[ $name ]);
// append meta query
$meta_query = array(
array(
'key' => $name,
'value' => $value,
'compare' => 'IN',
)
);
}
// update meta query
$query->set('meta_query', $meta_query );
}
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
register_taxonomy_for_object_type('category', 'projekte'); // Register Taxonomies for Category
$labels = array(
'name' => __('Projekte', 'projekte'), // Rename these to suit
'singular_name' => __('Projekt', 'projekte'),
'add_new' => __('Projekt hinzufügen', 'projekte'),
'add_new_item' => __('Neues Projekt hinzufügen', 'projekte'),
'edit' => __('Bearbeiten', 'projekte'),
'edit_item' => __('Projekt bearbeiten', 'projekte'),
'new_item' => __('Neues Projekt', 'projekte'),
'view' => __('Anschauen', 'projekte'),
'view_item' => __('Projekt anschauen', 'projekte'),
'search_items' => __('Projekte durchsuchen', 'projekte'),
'not_found' => __('Projekt wurde nicht gefunden', 'projekte'),
'not_found_in_trash' => __('Projekt wurde nicht im Papierkorb gefunden', 'projekte')
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'hierarchical' => true, // Allows your posts to behave like Hierarchy Pages
'has_archive' => true,
'supports' => array(
'title',
'excerpt'
), // Go to Dashboard Custom HTML5 Blank post for supports
'can_export' => true, // Allows export in Tools > Export
'taxonomies' => array(
'category',
) // Add Category and Post Tags support
);
register_post_type('projekte', $args);
archive-projekte.php:
<div id="archive-filters">
<?php foreach( $GLOBALS['my_query_filters'] as $key => $name ):
// get the field's settings without attempting to load a value
$field = get_field_object($key, false, false);
// set value if available
if( isset($_GET[ $name ]) ) {
$field['value'] = explode(',', $_GET[ $name ]);
}
// create filter
?>
<div class="filter" data-filter="<?php echo $name; ?>">
<?php create_field( $field ); ?>
</div>
<?php endforeach; ?>
</div>
<script type="text/javascript">
(function($) {
// change
$('#archive-filters').on('change', 'input[type="checkbox"]', function(){
// vars
var url = '<?php echo home_url('projekte'); ?>';
args = {};
// loop over filters
$('#archive-filters .filter').each(function(){
// vars
var filter = $(this).data('filter'),
vals = [];
// find checked inputs
$(this).find('input:checked').each(function(){
vals.push( $(this).val() );
});
// append to args
args[ filter ] = vals.join(',');
});
// update url
url += '?';
// loop over args
$.each(args, function( name, value ){
url += name + '=' + value + '&';
});
// remove last &
url = url.slice(0, -1);
// reload page
window.location.replace( url );
});
$('.button.acf-add-checkbox').parent().remove();
})(jQuery);
</script>
<div class="projekt-archive">
<?php
$args = array(
'post_type' => 'projekte',
'post_status' => 'publish',
'posts_per_page' => '-1'
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) : ?>
<?php while ( $the_query->have_posts() ) : ?>
......
<?php
endwhile;
endif;
?>
<?php wp_reset_query(); ?>
I used your code to try and recreate your issue and ran into a number of issues but got it working. On the link you supplied the video tutorial does things differently to the sample code.
The first thing I noticed is that you are changing the $query in the functions then redefining it in archive-projekte.php
$args = array(
'post_type' => 'projekte',
'post_status' => 'publish',
'posts_per_page' => '-1'
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) :
//......
endwhile;
endif;
wp_reset_query();
you can just use a version of the standard loop instead
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
//.......
}
}
Secondly when I set the advanced custom field(mitglieder) in Wordpress admin to be a checkbox it is then rendered as a checkbox on the front end by create_field() in the filter div but the problem is that checkboxes are saved in the meta data as serialized data so it didn't work so I changed the advanced custom field to a radio button it all works fine.
The new issue created by this is that the filter div now has radio buttons. So I watched the video tutorial and output checkboxes using a foreach loop on $field instead of using create_field, this means that the javascript needs to be changed also.
Now the only issue remains is if you need you advanced custom field to be checkbox sothat one of your projekte posts to have more than one mitglieder value then you would need to work with the serialized meta data in order to make the filter work correctly.
This works like ACF example video which uses houses and bedrooms and in that case a house cannot be a 2 bedroom house and a 3 bedroom house at the same time.
I have this URL for my Resort page page-resorts.php:
http://localhost/testwordpress/resorts/
After clicking the link to a post under Resort custom page I will have this URL for my custom page template (CPT) single-resort.php:
http://localhost/testwordpress/resort/kurumba-maldives/
As you can see the resorts was changed to resort because I can't use resorts slug for the slug post.
How can I achive this kind of URL:
http://localhost/testwordpress/resorts/kurumba-maldives/
where the resorts word is used and not resort word only?
I've heard about custom slug and search for it, but I still can't understand it.
You can create your custom post type this way.
function create_posttype() {
register_post_type( 'resort',
array(
'labels' => array(
'name' => __( 'Resorts' ),
'singular_name' => __( 'Resort' )
),
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'resorts'),
)
);
}
add_action( 'init', 'create_posttype' );
'rewrite' => array('slug' => 'resorts'), this used to add the slur on URL. this way you can acheive your URL.
Or you can override your current slug in functions.php
add_filter( 'register_post_type_args', 'wpse247328_register_post_type_args', 10, 2 );
function wpse247328_register_post_type_args( $args, $post_type ) {
if ( 'resort' === $post_type ) {
$args['rewrite']['slug'] = 'resorts';
}
return $args;
}
For more, please visit.
register post type
Change Custom Post Type slug
I want to change the default post permalink structure from (example.com/post-name) to (example.com/author_firstname-author_lastname/post-name).
I tried to add a new rewrite tag which I could use in the custom permalink structure to use the author first name and last name in the URL but it didn't work (404 error page).
add_filter('post_link', 'pauthor_permalink', 10, 3);
add_filter('post_type_link', 'pauthor_permalink', 10, 3);
function pauthor_permalink($permalink, $post_id, $leavename) {
add_rewrite_tag( '%pauthor%', '(.+)', 'pauthor=' );
if (strpos($permalink, '%pauthor%') === FALSE) return $permalink;
// Get post
$post = get_post($post_id);
if (!$post) return $permalink;
// Get Author Data
$post_author = get_post_field( 'post_author', $post->ID );
$user_info = get_userdata($post_author);
$first_name = $user_info->first_name;
$last_name = $user_info->last_name;
$pauthor = $first_name.'-'.$last_name;
return str_replace('%pauthor%', $pauthor, $permalink);
}
any help!?
Changing the Permalink structure in wordpress can be done without any sort of php.
See Settings > Permalinks
https://codex.wordpress.org/Settings_Permalinks_Screen
The structure you are looking for appears to be /%author%/%postname%/
More tags can be found here:
https://codex.wordpress.org/Using_Permalinks#Structure_Tags
Creating Custom Tags
You can create custom tags by creating a new taxonomy with 'rewrite' => true, for example:
add_action( 'init', 'my_rating_init' );
function my_rating_init() {
if ( ! is_taxonomy( 'rating' ) ) {
register_taxonomy(
'rating',
'post',
array(
'hierarchical' => FALSE,
'label' => __( 'Rating' ),
'public' => TRUE,
'show_ui' => TRUE,
'query_var' => 'rating',
'rewrite' => true
)
);
}
}
Source: https://wordpress.stackexchange.com/questions/168946/add-more-structure-tag-to-permalink
I need my post permalinks to include a custom taxonomy value, type, like this:
http://staging.mysite.com/article/post-title
Where article is that post's type taxonomy value. I've gotten this to work, but the problem I'm running into is that now all of my site's pages are 404ing. My custom post type and normal post urls work as intended, it's just page urls that are broken. Here is the code that causes the issue with page urls:
// Type taxonomy (no issues here)
function create_type_taxonomy() {
register_taxonomy(
'type',
'post',
array(
'labels' => array(
'name' => 'Type',
'add_new_item' => 'Add New Type',
'new_item_name' => 'New Type'
),
'show_ui' => true,
'show_tagcloud' => false,
'hierarchical' => false,
'rewrite' => array(
'slug' => 'type',
'with_front' => true
),
)
);
}
add_action( 'init', 'create_type_taxonomy', 0 );
add_action( 'init', 'st_default_post_type', 1 );
// Re-register built-in posts with a custom rewrite rule
function st_default_post_type() {
register_post_type( 'post', array(
'labels' => array(
'name_admin_bar' => _x( 'Post', 'add new on admin bar' ),
),
'public' => true,
'_builtin' => false,
'_edit_link' => 'post.php?post=%d',
'capability_type' => 'post',
'map_meta_cap' => true,
'hierarchical' => false,
'rewrite' => array( 'slug' => '%type%', 'with_front' => false ), // custom rewrite rule
'query_var' => false,
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
) );
}
add_filter('post_type_link', 'st_posts_permalink_structure', 10, 4);
// Replace custom rewrite rule on posts (%type%) with the taxonomy value
function st_posts_permalink_structure($post_link, $post, $leavename, $sample){
if ($post->post_type != 'post') {
var_dump($post->post_type);
return $post_link;
}
else{
if (strpos($post_link, '%type%') === FALSE){
return $post_link;
}
$post = get_post($post);
if (!$post){
return $post_link;
}
$terms = wp_get_object_terms($post->ID, 'type');
if ( !is_wp_error($terms) && !empty($terms) && is_object($terms[0]) ){
$taxonomy_slug = $terms[0]->slug;
}
else{
$taxonomy_slug = 'type';
}
return str_replace('%type%', $taxonomy_slug, $post_link);
}
}
Hoping another set of eyes might catch something that would cause page permalinks to 404. I've already tried just changing the permalinks setting in the admin to be /%type%/%postname%/, but this has the same issue. I found a couple other questions here that looked like the same issue I have, but none of them were answered:
WordPress Taxonomy Causing Pages to 404
When I add custom post type permalink rewrite, my regular post permalinks stop working. Can't get both to work at the same time
Hi I know this is a late answer, I had this issue today and found this info:
https://rudrastyh.com/wordpress/taxonomy-slug-in-post-type-url.html
Credit goes to: Misha Rudrastyh for this answer obviously, he has not used the rewrite declaration in his cpt instead seems to use filters to do the same thing, this got me past all my posts and pages 404ing.
To quote his code for posterity, he explained to use this code to solve the issue:
function rudr_post_type_permalink($permalink, $post_id, $leavename) {
$post_type_name = 'post_type_name'; // post type name, you can find it in admin area or in register_post_type() function
$post_type_slug = 'post_type_name'; // the part of your product URLs, not always matches with the post type name
$tax_name = 'custom_taxonomy_name'; // the product categories taxonomy name
$post = get_post( $post_id );
if ( strpos( $permalink, $post_type_slug ) === FALSE || $post->post_type != $post_type_name ) // do not make changes if the post has different type or its URL doesn't contain the given post type slug
return $permalink;
$terms = wp_get_object_terms( $post->ID, $tax_name ); // get all terms (product categories) of this post (product)
if ( !is_wp_error( $terms ) && !empty( $terms ) && is_object( $terms[0] ) ) // rewrite only if this product has categories
$permalink = str_replace( $post_type_slug, $terms[0]->slug, $permalink );
return $permalink;
}
add_filter('request', 'rudr_post_type_request', 1, 1 );
function rudr_post_type_request( $query ){
global $wpdb;
$post_type_name = 'post_type_name'; // specify your own here
$tax_name = 'custom_taxonomy_name'; // and here
$slug = $query['attachment']; // when we change the post type link, WordPress thinks that these are attachment pages
// get the post with the given type and slug from the database
$post_id = $wpdb->get_var(
"
SELECT ID
FROM $wpdb->posts
WHERE post_name = '$slug'
AND post_type = '$post_type_name'
"
);
$terms = wp_get_object_terms( $post_id, $tax_name ); // our post should have the terms
if( isset( $slug ) && $post_id && !is_wp_error( $terms ) && !empty( $terms ) ) : // change the query
unset( $query['attachment'] );
$query[$post_type_name] = $slug;
$query['post_type'] = $post_type_name;
$query['name'] = $slug;
endif;
return $query;
}
In addition like I said you will not need to declare the "rewrite" portion in the CPT arguments, you can leave the filters to handle that "after the fact" type thing.