I have a routes file as below and am getting an error saying "ccYear expected to be a string". Maybe I'm not following the implementation, but what I expect is that I have several routes.add(...), and whatever I put in the 2nd parameter will be matched to see if the incoming routes matches the parameter with a regex compare. Once one is found (in order of added), the route is executed to the /pages/{third parameter}.
I have two issues. First, is if I only have one route
routes.add("r1","/session/:ccYear([0-9][0-9][0-9][0-9])/sort/title","sessionPageByTitle");
I get the error "ccYear expted to be a string. My URL is /session/2018/sort/title
The second issue, is when I have multipe route add, I don't get the first route matched processed. I either get 404 or this ccYear error. Here is the order of the adds
routes.add(
"sessionWithYearSlug",
"/session/:ccYear([0-9][0-9][0-9][0-9])/:sessionSlug",
"sessionPageDetail"
);
routes.add(
"sessionWithYearSortTimeRoute",
"/session/:ccYear([0-9][0-9][0-9][0-9])/sort/time",
"sessionPageByTime"
);
routes.add(
"sessionWithYearSortTitleRoute",
"/session/:ccYear([0-9][0-9][0-9][0-9])/sort/title",
"sessionPageByTitle"
);
routes.add(
"sessionWithJustYearRoute",
"/session/:ccYear([0-9][0-9][0-9][0-9])",
"sessionPageByTitle"
);
routes.add(
"sessionWithJustYearRoute",
"/session/:ccYear([0-9][0-9][0-9][0-9])",
"sessionPageByTitle"
);
routes.add("sessionWithNoParamsRoute", "/session", "sessionPageByTime");
routes.add(
"sessionSortByTitleRoute",
"/session/:ccYear/sort/title",
"sessionPageByTitle"
);
routes.add(
"sessionSortByTimeRoute",
"/session/:ccYear/sort/time",
"sessionPageByTime"
);
About the first issue, you can remove the regex of ccYear,
routes.add(
"sessionWithYearSlug",
"/session/:ccYear/:sessionSlug",
"sessionPageDetail"
);
Keep it as a string, if user enter a wrong year, it will automatically redirect to 404 page.
For the second issue, I'm still not sure what is happened, please give more specific error message.
Related
When I try to programmatically update an order during a WP_Ajax hook. IE.
$order = wc_create_order($order_data);
$order->add_product( get_product( $membership_product_ids[0] ), 1 );
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
$order_id = $order->id;
$order->update_status('completed');
I get the following errors:
Warning: DOMXPath::query(): Invalid expression in /wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php on line 299
Warning: DOMXPath::query(): Invalid expression in /wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php on line 299
Warning: Invalid argument supplied for foreach() in /wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php on line 302
Warning: DOMXPath::query(): Invalid expression in /wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php on line 299
Warning: DOMXPath::query(): Invalid expression in /wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php on line 299
Warning: Invalid argument supplied for foreach() in /wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php on line 302
If I remove that update_status function it does not errors.
The errors you are seeing are coming from the notification system. Your code appears able to update the status just fine. The Emogrify Class is used to generate inline CSS in an HTML template. You are likely seeing these errors because either A) you have overridden the "Completed order" email template and have created a parsing error or B) there is a WooCommerce add-on that is conflicting in some way with what you are doing.
To correct the issue, the first step will be to verify that it is the notification system by going into the admin under WooCommerce->Settings->Email->Completed order and un-checking the "Enable this email notification" box. Then save that and retest.
If your error goes away, then check your theme directory for an override of that template. It would be in <themename>/woocommerce/emails/customer-completed-order.php. If you have one, them rename it so it will not override anymore and reactivate the "Completed order" notification and see if using the default template corrects the issue.
If the issue persists with the default email notification template, then disable all of the WooCommerce add-ons you might have installed and retest. At this point, if it is working, you can re-enable them one-by-one until the issue returns. Once you have found the offending add-on, you will need to either adjust your code to allow for the add-on to not cause an issue or contact the add-on developer to address you issue.
I am not sure but you could try this trick using new WC_Order( $order_id );, to avoid the error:
// global $woocommerce; // in case of need…
$order = wc_create_order($order_data);
$order_id = $order->id; // moving this here
$_order = new WC_Order( $order_id ); // here
$_order->add_product( get_product( $membership_product_ids[0] ), 1 );
$_order->set_address( $address, 'billing' );
$_order->set_address( $address, 'shipping' );
$_order->update_status('completed');
I agree this is a strange issue.
As it is rare issue, you'd better manually open:
/wp-content/plugins/woocommerce/includes/libraries/class-emogrifier.php
and before line 299, insert these lines, and see what you will get:
var_dump($value);
var_dump($this->translateCssToXpath($value['selector']));
var_dump($xpath->query($this->translateCssToXpath($value['selector'])));
I figured this out by trying a range of different hooks, the issue was that the hook I was using to create the order happened before woocommerce initialized that what caused this issue.
I have a web-app made in Drupal 8, and I have some routing problems. Users will login using an external service, and after login they are sent to the path /user/{user}, where {user} is their user id. I want to change this behaviour and send them to a page /dashboard. Not having access to what the external service routing is doing, I need to reroute /user/{user} to /dashboard. It seems like the drupal 8 redirect module could solve the problem, but I am not too keen on using an external module just for this simple task.
Because of this, I tried to change the route with drupal's RouteSubscriber and alterRoutes method. So I made my RouteSubscriber class in my module called "module" like this:
class RouteSubscriber extends RouteSubscriberBase {
protected function alterRoutes(RouteCollection $collection) {
if ($route = $collection->get('user.page')) {
$route->setDefaults(array(
'_controller' => '\Drupal\module\Controller\Dashboard::content',
));
}
if ($route = $collection->get('entity.user.canonical')) {
$route->setDefaults(array(
'_controller' => '\Drupal\module\Controller\Dashboard::content',
));
}
}
}
The route user.page has path /user, and the path entity.user.canonical is the route I'm interested in, which has path /user/{user}, where {user} is again a path parameter. When I go to the page /user, the dashboard is displayed as expected, but going to for example /user/123 does not show the dashboard, but seems display what the route originally did. Just to test whether it was impossible to alter this route, I tried to set all routes to have display the dashboard by inserting the following code into RouteSubscriber:
foreach ($collection->all() as $route) {
$route->setDefaults(array(
'_controller' => '\Drupal\module\Controller\Dashboard::content',
'pid' => '',
'uid' => '',
'modifier' => '',
'display' => '',
));
}
The junk pid, uid, modifier and display are just defaults to different routes path parameters so the code will run. This makes the page /user/123 correctly display the dashboard! However, I do get the following error message at the bottom of the screen:
The website encountered an unexpected error. Please try again later.
Symfony\Component\Routing\Exception\MissingMandatoryParametersException: Some mandatory parameters are missing ("filter") to generate a URL for route "devel.configs_list". in Drupal\Core\Routing\UrlGenerator->doGenerate() (line 182 of core/lib/Drupal/Core/Routing/UrlGenerator.php).
So, what am I doing wrong here? Can what I want be done, or should I do something different to achieve what I want? Also, feel free to ask for more code if needed!
I'm facing a weird issue on Wordpress…
I have to do some minor content updates on a Wordpress online since 2020, running perfectly.
But for only one of the CPT, when I want to add/modify a post, the publish/update (and save as draft) buttons not working. I can click on them but nothing happens…
In my console, I spot the following errors :
400 Bad Request GET https://mywebsite/wp-json/wp/v2/challenges?per_page=100&exclude=1921&parent_exclude=1921&orderby=menu_order&order=asc&_fields=id%2Ctitle%2Cparent&context=edit&_locale=user
Uncaught (in promise)
Object { code: "rest_invalid_param", message: "Paramètre(s) non valide(s) : orderby", data: {…} } in data.min.js:2:32702
I can update content without any problem with the quick edit…
Has anyone ever encountered this error?
I found a fix here :
Tim Ross webdevelopment
I had to add to functions.php the following code :
// This enables the orderby=menu_order for Posts
add_filter( 'rest_post_collection_params', 'filter_add_rest_orderby_params', 10, 1 );
// And this for a custom post type called 'portfolio'
add_filter( 'rest_challenges_collection_params', 'filter_add_rest_orderby_params', 10, 1 );
//Add menu_order to the list of permitted orderby values function filter_add_rest_orderby_params( $params ) {
$params['orderby']['enum'][] = 'menu_order';
return $params;
}
The filter hook is called rest_{post_type}_collection_params.
In my case, the post_type is "challenges".
How to retrive wp_get_current_user() inside a register_rest_route callback (Wordpress site)?
I'm just trying to do a simple hello wp_get_current_user()->user_login on a php test page:
add_action('rest_api_init', 'helloTest');
function helloTest() {
register_rest_route('hello', 'hello/(?P<id>\d+)', array(
'methods' => WP_REST_SERVER::READABLE,
'callback' => 'showHello'
));
}
function showHello($someVariable) {
echo "Hello " . wp_get_current_user()->user_login . $someVariable;
}
But wp_get_current_user() is null and wp_get_current_user->ID is 0;
I dont want to authenticate the user again. I just want to retrieve his username. If he is not logged in, just show empty an empty string.
If I have to authenticate again, how to add a "nonce" to it? On internet I just have examples using javascript, but not directly on PHP methods.
Issues in your code
First off, you should understand properly how to add custom WP REST API endpoints:
An endpoint's namespace (the first parameter passed to register_rest_route()) should be in this format: your-plugin/v<version>. E.g. hello/v1 or hello-world/v1 and not just hello or hello-world.
$someVariable (the first parameter passed to your endpoint callback function) is not just any variable — it's an instance of the WP_REST_Request class — and shouldn't be echo-ed like what you did here:
function showHello($someVariable) {
echo "Hello " . wp_get_current_user()->user_login . $someVariable;
}
And normally, the $someVariable is better be changed to $request (i.e. rename it to "request").
And you should return a valid WP REST API response. For example, to return just the username:
return new WP_REST_Response( wp_get_current_user()->user_login, 200 );
And know your own API endpoint URL..
(based on your original namespace)
/wp-json/hello/hello/1 <- correct
/wp-json/hello/?John <- incorrect
because in your code, the parameter is a number and not string: (?P<id>\d+)
I hope those help you, and once again, do read the handbook for a more detailed guide.
The Corrected Code
add_action( 'rest_api_init', 'helloTest' );
function helloTest() {
register_rest_route( 'hello/v1', 'hello/(?P<id>\d+)', array(
'methods' => WP_REST_SERVER::READABLE,
'callback' => 'showHello'
) );
}
function showHello( $request ) {
return new WP_REST_Response( wp_get_current_user()->user_login, 200 );
}
Now about getting the user (from the API endpoint — showHello())
If I have to authenticate again, how to add a "nonce" to it?
Just because the user is logged-in/authenticated to the (WordPress) site, it doesn't mean the user is automatically logged-in to the WP REST API. So yes, you'd need to either provide a nonce along with your API request, or use one of the authentication plugins mentioned right here.
Now in most cases, GET (i.e. read-only) requests to the API do not need any authentication, but if you'd like to retrieve the data of the currently logged-in user on your site, then one way is via the _wpnonce data parameter (either POST data or in the query for GET requests).
Example for a GET request:
http://example.com/wp-json/wp/v2/posts?_wpnonce=<nonce>
So based on your comment and the corrected code (above):
Theres no "code" that make the request. Its is just an anchor that
calls my route: Hello
You can add the nonce as part of the URL query string like so: (the namespace is hello/v1 and the <id> is 1)
// Make request to /wp-json/hello/v1/hello/<id>
$nonce = wp_create_nonce( 'wp_rest' );
echo 'Hello';
So try that out along with the corrected code and let me know how it goes. :)
And once again, be sure to read the REST API authentication handbook.
I'm trying to use params on my main route. But in fact the params are not set and they are used in the path :
Router.map(function funcClientRouterMap(){
this.route('home', {
path: '/:_redirect?',
action: function funcClientRouterMapAction(){
console.log(this.path, this.params);
}
})
});
now if i try manual redirection here is what i get :
Router.go('home'); // it redirects on / => ok
Router.go('home', {_redirect: test}); // this.path = /test, and this.params is empty
How can i use _redirect like a params and not a route ?
Thanks
Router.go accepts a path as its first argument (per the docs). So if you were trying to programmatically cause the same result as the user going to /redirectMeSomewhere, you just use:
Router.go('/redirectMeSomewhere');
And this.params._redirect should be 'redirectMeSomewhere'.
Note that like #apendua implies, if you have other routes it could cause chaos to have a route defined as /:anything, because the other routes may never get triggered. If the above doesn't do the trick, try commenting out all your other routes to see if that changes anything.