themosis / framework

The Themosis framework core.
https://framework.themosis.com/
GNU General Public License v2.0
671 stars 121 forks source link

Dynamic/Wildcard routing #66

Closed ramon-villain closed 9 years ago

ramon-villain commented 9 years ago

I still don't understand how we work with wildcard in this Route class. Seems more complicated than the Laravel's way.

So instead of dynamic slug/permalink we've to add every post? For example, I created a 'buildings' post-type, and I want to have a 'buildings' page (ex: http://site/buildings), that will list all of my buildings (I suppose this is an ArchiveType), and a building page (ex: http://site/buildings/example), loading the specific content for that building, how we do this?

fabianmarz commented 9 years ago

:+1: routing is working fine, while not using mod_rewrite...but i need mod_rewrite enabled permalinks :)

jlambe commented 9 years ago

The class Route is an enhanced if statement. So apart the name, behind you still have to use the WordPress way of doing routing. There is nothing like this available for example:

Route::get('/*', function(){});

So regarding your custom post type, registered with a slug name of buildings, you'll write this code:

// The archive type - Listing of all buildings - http://mysite.com/buildings/
Route::get('postTypeArchive', array('buildings', function()
{
    // Note that the WordPress loop that returns your custom post types is only the 10 or so latests entries - The number of entries is defined in the WordPress admin settings 'number of posts'. You can also write a custom query now and pass it to your view
    return 'Hello World!';
}));

// Route for all single buildings posts - http://mysite.com/buildings/example/ - http://mysite.com/buildings/example-2/ - ...
Route::get('singular', array('buildings', function()
{
    return 'Same view for all individual building post';
}));

// Now for a specific building entry - http://mysite.com/buildings/example/
Route::get('single', array(array('example', 105), function()
{
    return 'View for this specific post only';
}));

Also like @fabianmarz said, you need to set a permalink structure to make this working using explicit URI. Otherwise you can only specify the ID of an element in the route methods.

When creating posts/pages/custom post types, WordPress automatically assigned the URI for the posts so you don't have to manage it. But you can modify it to your need inside the admin.

Let me know if it works for you. Otherwise post your custom post type code.

fabianmarz commented 9 years ago

@jlambe if i set the standard permalink in Wordpress, like http://example.com/?p=113 the Page route is working fine. But after setting a permalink slug structure like http://example.com/example-page the route resolves to 404 (no route defined) page.

Do I have to define something else to get this work properly?

jlambe commented 9 years ago

It's weird a page route is working with the query parameter ?p. This query parameter is only use for posts et posts types normally. For pages, the query parameter should be page_id.

Can you post your code ?

fabianmarz commented 9 years ago

Ok, that's odd...now it's working properly without any change :-O Sorry for inconvenience!

ramon-villain commented 9 years ago

So my point is, if I develop a webapp, like a bakery shop, to a customer using TH and post-type 'products'. I'll need to stay updating this array manually for natural?

ramon-villain commented 9 years ago
$query = new WP_Query(array(
            'post_type'         => 'empreendimentos',
            'posts_per_page'    => -1,
            'post_status'       => 'publish'
        ));
$ids=[];
foreach($query->get_posts() as $post){
    $ids[] = $post->ID;
}

Route::get('single', array($ids, function(){

    return 'Hello World!';

}));

This kind of query isn't in the core?

ramon-villain commented 9 years ago

I tried all the examples above… I have this post-type 'empreendimentos'

// 1
Route::get('postTypeArchive', array('empreendimentos', function()
{
    return 'Same view for all individual building post';
}));

// 2
Route::get('singular', array('empreendimentos', function()
{
    return 'Same view for all individual building post';
}));

//3
Route::get('single', array([99], function(){

    return 'Hello World!';

}));

//4 -> Using that query
Route::get('single', array($ids, function(){

    return 'Hello World!';

}));

My permalink is set to: Post name http://jetavares.sys/post-example/

My application:

PostType::make('empreendimentos', 'Empreendimentos', 'Empreendimento')->set([
    'public'        => true,
    'menu_position' => 20,
    'supports'      => array('title'),
    'query_var'     => false,
    'labels'        => [
        'all_items'   => __('Todos Empreend.'),
        'add_new'   => __('Adicionar Empreend.')
    ]
]);
ramon-villain commented 9 years ago

Gosh I suppose that 'query_var' is fuckin me. hahahah dammit

jlambe commented 9 years ago

There are multiple ways to implement this.

  1. Set a WordPress page that is reponsible to display a complete list of products. You define a page route and inside that route, you run a custom query/loop to display your products. (solution if you don't want your custom post type to be publicly queryable)
  2. Or using the default postTypeArchive, you could hook to the pre_get_posts action and modify the main query properties by changing the posts_per_page value so when listening to the postTypeArchive, you'll get not 10 but all products.

In the example you gave above, what you're trying to achieve is to display the view/page for a single product. So the route would be:

Route::get('singular', array('empreendimentos', function()
{
    return 'Viewing details of a product';
}));

But yes, the query var is set to false so this won't work. By default, the query_var is set to the custom post type slug name. Also, you have to set your custom post type as public, otherwise you can't query it using the default behaviour of WordPress, only on doing custom WP_Query.

ramon-villain commented 9 years ago

Thank you for the job and patiance, hahaha I was bothering you, I know :+1:

jlambe commented 9 years ago

No problem at all. I like helping others ;)

xyNNN commented 5 years ago

When I try to implement a dynamic route like Route::get('profil/{username}', 'UserController@profile')->name('user.profile'); it resolves to the specified action without any problem but the page title is "Page not found" which is the default behaviour of WordPress that this is a 404 page.

How can I solve this? Thanks in advance!

jlambe commented 5 years ago

@xyNNN Hello, please open your own issue so we can better track it the next time. To solve your problem, you can use the document_title_parts filter from your controller method:

Filter::add('document_title_parts', function ($parts) {
    $parts['title'] = __('Your Custom Page Title', APP_TD);
    return $parts;
});

You can call this from from the controller method. I generally put this in a trait.

xyNNN commented 5 years ago

sorry @jlambe - next Time I will create a separate issue for better tracking, sure! Thanks mate, but this hint works perfectly :)

Where do you think we can add this piece of useful information in the documentation? Perhaps we put this into the Controller part? If you agree I would prepare some pull request in the documentation repository.

jlambe commented 5 years ago

@xyNNN The route documentation could be a better place I think as the filter can be run from a closure as well. Thank you for proposing a PR on the docs 👏 Make sure to send a PR against the 2.0 branch ;)

xyNNN commented 5 years ago

By the way ... How do you solve it when you mean that you will implement this feature in a trait?

xyNNN commented 5 years ago

https://github.com/themosis/documentation/pull/80

Wish you a nice weekend! xyNNN