I am working on a Symfony(4.4) project. I am trying to make eventSubscriber that will redirect user with locale based on saved cookie. The idea is when I visit homepage for first time(or if I have not saved cookie) I have to redirect myself to homepage with the default locale(which is 'en' in my case). When I change the locale I save the new locale in cookie (for example my cookie is "LOCALE" => 'de'). When I enter in homepage next time I have to redirect myself with the 'de' locale(because it's saved on the cookie). When I set the priority to 32+ I get redirect to the default locale instead the cookie locale(I receive the cookie content, so the problem is not from the cookie), else if I set the priority before 32 I get the error "Route not found for '/' " https://imgur.com/0YAtgqs. For now I made this:
I added new method in RequestSubscriber:
public function redirectToCookieLocale(RequestEvent $event)
{
if ($event->isMasterRequest() === false) {
return;
}
$request = $event->getRequest();
$path = $event->getRequest()->getPathInfo();
$cookieLocale = $request->cookies->get('LOCALE');
if ($cookieLocale != null && $this->isValidLocale($cookieLocale)) {
$locale = $request->cookies->get('LOCALE');
} else {
$locale = $request->getDefaultLocale();
}
if ($path == '/') {
$event->setResponse(new RedirectResponse(
$this->generator->generate(
'frontend_index',
['_locale' => $locale]
),
301
));
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [
['redirectToCookieLocale', 30]
]
];
}
Also I created ResponseSubscriber where I create the cookie:
public function onKernelResponse(ResponseEvent $event)
{
$request = $event->getRequest();
$response = $event->getResponse();
if ($response->isRedirection()) {
return;
}
$urlLocale = $request->get('_locale');
$cookieLocale = $request->cookies->get('LOCALE');
if ($urlLocale != null && $urlLocale != $cookieLocale) {
$cookie = new Cookie('LOCALE', $request->getLocale(), (time() + 3600 * 24 * 7), '/', '', '', false);
$response->headers->setCookie($cookie);
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => [
['onKernelResponse', 0],
],
];
}
Related
I have a translation in my project for templates and routes. when the locale is set, the translations are working except the locale parameter in the links is not correct.
my default language is NL. so I have a page www.website.com/nl/contact
when I switch to language fr I go to www.website.com/fr/contact, then when I go to look in the HTML source, the link is again www.website.com/nl/contact in stead of www.website.com/fr/contact so the locale parameter in the links is not updated regarding the setLocale
my module.php
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach(
\Zend\Mvc\MvcEvent::EVENT_DISPATCH_ERROR,
function ($e) {
$application = $e->getApplication();
$match = $application->getMvcEvent()->getRouteMatch();
if (null === $match) {
$params = [
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'not-found',
// Here you can add common params for your application routes
];
$viewModel = $e->getViewModel();
$viewModel->setTemplate('layout/website');
$routeMatch = new RouteMatch($params);
$routeMatch->setMatchedRouteName('home');
$application->getMvcEvent()->setRouteMatch(
$routeMatch
);
}
}
);
$moduleRouteListener = new ModuleRouteListener();
if (!$e->getRequest() instanceof ConsoleRequest) {
$this->setLanguage($e);
$eventManager->attach('route', array($this, 'onPreRoute'), 100);
$moduleRouteListener->attach($eventManager);
$this->initAcls($e);
if (isset($_SERVER['APP_ENV']) and $_SERVER['APP_ENV'] == 'production') {
$eventManager->attach('finish', array($this, 'outputCompress'), 100);
}
}
}
private function setLanguage($e)
{
$redirectBase = $e->getRequest()->getServer()->get('REDIRECT_BASE');
$requestUri = $e->getRequest()->getServer()->get('REQUEST_URI');
$cmsString = substr($requestUri, strlen($redirectBase), 4);
$language = 'nl';
$routeTranslation = true;
if ($requestUri != '/') {
$language = substr($requestUri, 1, 2);
}
if ($cmsString == 'cms/') {
$language = 'en-us';
$routeTranslation = false;
}
$translator = $e->getApplication()->getServiceManager()->get('MvcTranslator');
$translator->setLocale($language);
if ($routeTranslation) {
$translator->addTranslationFile('PhpArray', __DIR__.'/../language/Routes/' . $language . '.php', 'default', $language);
}
}
public function onPreRoute($e)
{
$app = $e->getTarget();
$serviceManager = $app->getServiceManager();
$serviceManager->get('router')->setTranslator($serviceManager->get('MvcTranslator'));
}
I'm using Woocommerce REST API to retrieve some data, code provided by Woocommerce team to use as client
My client options:
'wp_api' => true,
'version' => 'wc/v1',
'ssl_verify' => false,
'wp_api_prefix' => '/wp-json/',
'query_string_auth' => true,
Have a function to retrieve subscriptions:
function get_wc_subscriptions($sid=0, $parent=null, $page=1, $offset=0)
{
$params['page'] = $page;
$params['offset'] = $offset;
$params['role'] = 'all';
if($sid > 0) {
$endpoint = 'subscriptions/'.$sid;
} else {
$endpoint = 'subscriptions';
}
if(isset($parent) && ($parent != null)) {
$params['filter[parent_id]'] = $parent;
}
return $this->wooClient->get($endpoint, $params);
}
Parent parameter is not working, when calling function without any params, I get a result of all subscriptions on first page, if parent is set, get same result with all subscriptions (not being filtered).
Am I missing something?
UPDATE:
How can I use get_wc_subscriptions?
require_once('woosync.php');
$sid = $_GET['sid'];
$parent = $_GET['parent'];
$woosync = new woosync();
$subscriptions = $woosync->get_wc_subscriptions($sid, $parent);
echo "<pre>";
print_r($subscriptions);
I'm a Laravel developer. I develop one ecommerce plugin with Laravel and I just want to combine WordPress with Laravel. So I need to share or make common login session between Laravel and WordPress.
How could I implement this? And are there special plugins available for this? Or could I use laravel-Auth?
The right way of doing it is to Have a Laravel (or Wordpress) as an Auth server
And create like an SSO plugin.
I was doing the same with NodeBB Forum login from Laravel.
Steps that I suggest:
Look at this package Laravel OAuth Server
Create or find any SSO plugin for wordpress
So you have all users in laravel (Registration and etc)
and if they want to login to Wordpress they login to Laravel App and give permission to login to wordpress.
Think of it Like you add Facebook Login to your site
Reading more for wordpress SSO
But to play with session and cookies it can be security issues.
Hope Helped.
Enabling Single-Sign-On in WordPress took me 18+ hours of struggle but might take you only a few minutes:
I experimented with all sorts of things: Laravel Passport (OAuth2), OpenID Connect, etc.
But the only solution I could get to work was to have the WordPress login page redirect to an auth-protected Laravel route that generates a JWT (JSON Web Token) and redirects back to a special callback URL on WordPress that either creates a new user or logs in an existing user.
It works well.
class JwtController extends Controller {
/**
* Inspired by https://github.com/WebDevStudios/aad-first-party-sso-wordpress/tree/master/lib/php-jwt
*
* #param Request $request
* #return ResponseInterface
*/
public function redirectWithToken(Request $request) {
$key = config('jwt.key');
$wpJwtUrl = $request->input('callback');
$redirectUrlAfterLogin = $request->input('redirect_to'); //Get the original intended destination and append as URL param to /jwt.
$tokenArray = $this->getToken(auth()->user(), $redirectUrlAfterLogin);
$jwt = \Firebase\JWT\JWT::encode($tokenArray, $key);
$wpJwtUrlWithTokenAsParam = $wpJwtUrl . '?token=' . $jwt;
return redirect()->away($wpJwtUrlWithTokenAsParam);
}
/**
*
* #param \App\User $user
* #param string $redirectUrlAfterLogin
* #return array
*/
public function getToken($user, $redirectUrlAfterLogin) {
$now = \Carbon\Carbon::now();
$aud = config('jwt.audience'); //root URL of the WordPress site
$firstName = StrT::getFirstNameFromFullName($user->name);
$expirationMins = config('jwt.expirationMins');
$token = [
"iss" => url("/"),
"aud" => $aud, //"audience" https://tools.ietf.org/html/rfc7519#section-4.1.3
"iat" => $now->timestamp, //"issued at" https://tools.ietf.org/html/rfc7519#section-4.1.6
"exp" => $now->addMinutes($expirationMins)->timestamp, //"expiration" https://tools.ietf.org/html/rfc7519#section-4.1.4
"attributes" => [
'emailAddress' => $user->email,
'firstName' => $firstName,
'lastName' => StrT::getLastNameFromFullName($user->name),
'nickname' => $firstName,
'displayName' => $user->name,
'redirectUrlAfterLogin' => $redirectUrlAfterLogin//In plugin: use redirectUrlAfterLogin from attributes after login.
]
];
return $token;
}
}
Install this WordPress plugin, but don't activate it until you're finished with everything else: https://wordpress.org/plugins/wp-force-login/
Install this WordPress plugin: https://as.wordpress.org/plugins/jwt-authenticator/
And then edit its auth.php to be this:
// register the callback
add_action('rest_api_init', function () {
register_rest_route('jwt-auth/v1', 'callback', [
'methods' => 'GET',
'callback' => 'ja_login'
], true);
});
require_once('JWT.php');
function ja_login() {
//get all attributes
$options = get_option('ja_settings');
$token_name = $options['token_name'];
$secret_key = $options['secret_key'];
$iss = $options['iss'];
$aud = $options['aud'];
// decode the token
$token = $_GET[$token_name];
$key = $secret_key;
$JWT = new JWT;
$json = $JWT->decode($token, $key);
$jwt = json_decode($json, true);
// use unix time for comparision
$exp = is_int($jwt['exp']) ? $jwt['exp'] : strtotime($jwt['exp']);
$nbf = $jwt['nbf'] ?? null;
$now = strtotime("now");
// if authentication successful
if (($jwt['iss'] == $iss) && ($jwt['aud'] == $aud) && ($exp > $now) && ($now > $nbf)) {
return getUserFromValidToken($options, $jwt);
} else {
return 'Login failed. Please let us know exactly what happened, and we will help you out right away.';
}
}
/**
*
* #param array $options
* #param array $jwt
* #return string
*/
function getUserFromValidToken($options, $jwt) {
$attributesKey = $options['attributes'];
$mail = $options['mail'];
$givenname = $options['first_name'];
$surname = $options['last_name'];
$nickname = $options['nickname'];
$displayname = $options['displayname'];
$default_role = $options['default_role'];
$attributes = $jwt[$attributesKey];
$redirectUrlAfterLogin = $attributes['redirectUrlAfterLogin'] ?? get_site_url();
$_SESSION['attributes'] = $attributes;
$_SESSION['jwt'] = $jwt;
// find or create user
$user = ja_find_or_create_user($attributes[$mail], $attributes[$mail], $attributes[$givenname], $attributes[$surname], $attributes[$nickname], $attributes[$displayname], $default_role);
// login user
if ($user) {
wp_clear_auth_cookie();
wp_set_current_user($user->ID, $user->user_login);
wp_set_auth_cookie($user->ID);
do_action('wp_login', $user->user_login);
wp_safe_redirect($redirectUrlAfterLogin);
exit();
} else {
return 'getUserFromValidToken failed!';
}
}
/**
*
* #param string $username
* #param string $emailAddress
* #param string $firstName
* #param string $lastName
* #param string $nickname
* #param string $displayName
* #param string $defaultRole
* #return mixed
*/
function ja_find_or_create_user($username, $emailAddress, $firstName, $lastName, $nickname, $displayName, $defaultRole) {
// if user exists, return user
if (username_exists($username)) {
return get_user_by('login', $username);
} elseif (email_exists($emailAddress)) {
return get_user_by('email', $emailAddress);
} else {// create user
$length = 16;
$include_standard_special_chars = false;
$random_password = wp_generate_password($length, $include_standard_special_chars);
// create user
$user_id = wp_create_user($username, $random_password, $emailAddress);
// update user metadata and return user id
$userData = [
'ID' => $user_id,
'first_name' => $firstName,
'last_name' => $lastName,
'nickname' => $nickname,
'display_name' => $displayName,
'role' => $defaultRole
];
return wp_update_user($userData);//(If successful, returns the user_id, otherwise returns a WP_Error object.)
}
}
/**
* Get login message link HTML for adding to the login form
* #return string
*/
function getLoginMessage() {
$options = get_option('ja_settings');
$redirect_to = $_GET['redirect_to'] ?? null;
$login_url = $options['login_url'] . '?callback=' . urlencode(site_url('/wp-json/jwt-auth/v1/callback'));
if($redirect_to){
$login_url .= '&redirect_to=' . urlencode($redirect_to);
}
$login_message = $options['login_message'];
return "<a id='jwt_link' href='{$login_url}'>{$login_message}</a>";
}
add_filter('login_message', 'getLoginMessage');
add_action( 'load-profile.php', function() {//https://wordpress.stackexchange.com/a/195370/51462 Redirect from profile.php to the dashboard since there is no reason for WordPress users to see or manage their profile since their main account is on the other site.
if( ! current_user_can( 'manage_options' ) ){
$redirectUrl = get_site_url();//admin_url()
exit( wp_safe_redirect( $redirectUrl ) );
}
} );
function show_admin_bar_conditionally(){//remove the WordPress admin toolbar https://premium.wpmudev.org/blog/remove-the-wordpress-admin-toolbar/
return current_user_can( 'manage_options' );
}
add_filter('show_admin_bar', 'show_admin_bar_conditionally');//can use 'show_admin_bar_conditionally' or '__return_false' for never.
//------------------------------------------------------------------
//for https://wordpress.org/support/topic/rest-api-26/#post-9915078
//and https://github.com/kevinvess/wp-force-login/issues/35
//and https://wordpress.org/support/topic/rest-api-26/page/2/#post-10000740
//and https://wordpress.org/support/topic/jwt-authentication/#post-10698307
add_filter( 'rest_authentication_errors', '__return_true' );
This belongs in functions.php of your theme in WordPress:
// https://codex.wordpress.org/Customizing_the_Login_Form
function my_custom_login_page() { ?>
<style type="text/css">
#loginform, #login #nav{display: none;}
#jwt_link{font-weight: bold; font-size: 20px;}
</style>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById('jwt_link').click();//immediately upon load of login page, click the JWT link automatically
});
</script>
<?php }
add_action( 'login_enqueue_scripts', 'my_custom_login_page' );
I can't get the request POST this my code
public function inscriptionAction() {
$session = $this->getRequest()->getSession();
$request = Request::createFromGlobals();
$myCat = new \ stdClass;
$privatekey=$request->request->get('privatekey');
$key=$request->request->get('key');
if ($key== 'NULL' or $privatekey == NULL ) {
return $this->render('GestionsFilmeBundle:public:identification.html.twig', array(
'message' => 'Parametres non fournies-----',));
}
}
but privatekey and key are null
If you are using the Symfony Framework you don't need to build the Request object, you can just have it automatically injected in to your action and then you can use it from there.
public function inscriptionAction(Request $request) {
$privateKey = $request->request->get('privatekey');
$key = $request->request->get('key');
if (null === $key || null === $privateKey) {
return $this->render(
'GestionsFilmeBundle:public:identification.html.twig',
array(
'message' => 'Parametres non fournies-----',
)
);
}
}
I am trying to execute and then display a cookie in my nav header template.
Currently my controller checks if a user is logged in. If not logged in then checks for a cookie. If no cookie exists a generic cookie is created. And then finally the template is loaded.
Currently the cookie is being created and template is loaded just fine, but the value passed when rendering the template does not show up after the page loads. I can see the cookie is created, and if I reload the page a 2nd time everything works as intended.
So I know this means the headers are not being sent as expected correct? But I cannot figure out the proper way to do this in Symfony2.
Here is my controller code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;
class navController extends Controller {
public function displayNavAction() {
$userState = '';
$userZipcode = '';
if ($this->container->get('security.context')->getToken() != null) {
// To check if user is authenticated or anonymous
if ($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') === true) {
$user = $this->getUser();
$userCity = $user->getCity();
$userState = $user->getState();
$userZipcode = $user->getZipcode();
} else {
//User is not logged in, so check for cookie.
$request = $this->get('request');
$cookies = $request->cookies;
if ($cookies->has('city'))
{
//User not logged in, but cookie exists. So use cookie.
$userCity = $cookies->get('city');
} else {
//User not logged in, and no existing cookie. So create cookie.
$cookieGuest = array(
'name' => 'city',
'value' => 'seattle',
'path' => '/',
'time' => time() + 3600 * 24 * 7,
false,
false
);
$cookie = new Cookie($cookieGuest['name'], $cookieGuest['value'], $cookieGuest['time'], $cookieGuest['path']);
$response = new Response();
$response->headers->setCookie($cookie);
$response->sendHeaders();
$userCity = $cookies->get('city');
}
}
}
return $this->render(
'trrsywxBundle:Default:nav.html.twig', array('city' => $userCity, 'state' => $userState, 'zipcode' => $userZipcode, 'tempjunk' => $userCity));
}
}
You are not using the response you created that's the problem try this :
$userCity = $cookies->get('city');
$response = new Response($this->render(
'trrsywxBundle:Default:nav.html.twig',array(
'city' => $userCity,
'state' => $userState,
'zipcode' => $userZipcode,
'tempjunk' => $userCity
)));
$cookie = new Cookie($cookieGuest['name'], $cookieGuest['value'],$cookieGuest['time'], $cookieGuest['path']);
$response->headers->setCookie($cookie);
$response->sendHeaders();
return $response;
then you can get cookie value in your twig using the request global {% app.request.cookies %}