Woocommerce, cart, and session - javascript

I'm running into a little problem with woocommerce's cart.
Description of the issue:
Say I am logged in, I have 3 products in the cart. If I log out, I have 0 products in the cart. I add a product and log back in. I'm now still having that product I added while being logged out. That is fine, as I suppose when you navigate and log in just at the checkout, you don't want old cart items to pop up suddenly. Now, if I log out, I have 0 products, which is also fine, as suddenly you become nobody and you can assume a new user will take on. But, if, with an empty cart I log back in, I now have the 3 products from the beginning, instead of having the 1 I had during my previous visit.
What I'd like to achieve. By default, in the above story, woocommerce would show a cart with 1 item like expected. But in the theme I build, I load the whole cart via ajax. I have a little function that basically just does this :
function sp_get_cart() {
$cart = WC()->cart->get_cart();
wp_send_json($cart);
}
add_action('wp_ajax_get_cart', 'sp_get_cart');
add_action('wp_ajax_nopriv_get_cart', 'sp_get_cart');
I also have the whole signon/signout part working with ajax. I tried to find in the woocommerce code things I may have missed, but I couldn't find anything. Should I do something specific when processing the signon or signout ? I thought I could just rely on the default behavior of woocommerce's session, but something seems broken, and when I log in with items in the cart, it seems these new cart items don't get added to the session stored in the database and when the next signon happens, the previous version is being loaded. Any help would be much appreciated.
edit: here is the logout function
function sp_logout() {
WC()->session->destroy_session();
wp_logout();
ob_clean();
// $_SESSION = array();
http_response_code(200);
wp_send_json(array('status' => 'OK'));
die();
}
add_action('wp_ajax_logout', 'sp_logout');
add_action('wp_ajax_nopriv_logout', 'sp_logout');

Try clearing $_SESSION global variable, on your log out function
$_SESSION = array();

Related

Cart session Not Found When Using Axios Post

I am trying to implement cart functionality using bumbummen99/LaravelShoppingcart where the user can increase/decrease quantities of items in their cart. Pressing '+' or '-' fires an onclick javascript function called updateCart().
updateCart() uses Axios to send a post request to my CartController#updateCart() where I run the logic to update the cart quantities.
Problem: I lose access to the global cart session after submitting the post request.
Once I'm in updateCart() in CartController, I can access the request
variables from axios successfully. However, I am unable to access my
cart session. I can't locate the cart items even though I have the
correct rowId.
My cart has items in it but typing Cart::content() or Cart::get() returns error 500 because it thinks my cart is empty.
As soon as I can retrieve my cart, I can implement the logic to update the quantity using Cart::update(), etc. Please help!
Hitting + or - triggers updateCart(action,rowId)
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function updateCart(action,rowId) {
axios.post('/api/update-cart', {
action: action,
rowId: rowId
}).then(response => console.log(response)).catch(error => {
console.log(error.response)
});
}
</script>
Api.php
Route::post('update-cart', 'CartController#updateCart')->name('update-cart');
CartController.php
public function updateCart(Request $request) {
//works, returns '620d670d95f0419e35f9182695918c68'
return $request->get('rowId');
//works, returns 'add' or 'subtract'
return $request->get('action');
//fails, returns empty array
return Cart::content();
//fails, error 500 because cannot find cart instance
return Cart::get('620d670d95f0419e35f9182695918c68');
return 200;
}
When ran, I lose access to Cart::content() and related Cart functions. It's trying to return Cart::content() which should display my entire cart.
this is when I return Cart::content() on any other page
You cannot access sessions within API routes.
APIs are based on tokens, not sessions. Read about "JWT" (JSON Web Token) or "OAuth" or "Laravel Passport".
You can still enforce sessions if you really want to:
Open app/Http/Kernel.php
Find protected $middlewareGroups =
Where you should see 'api' => [
Just add this:
\App\Http\Middleware\EncryptCookies::class,
I suggest you to use cart in database.
Let say someone use your api with web, then he was add to cart. Next day he back to your shop but use mobile app. So if we use session, i think its can not with api. But if use database, you can store cart data base on User ID right.

Mongo&Express - what are the practical ways to avoid client firing same req multiple times?

Introduction:
I am developing a liking system similar to normal facebook liking where each user can like each post only once. I need to develop this system and have a "totalLike" in mongoDB. Environment: Mongoose, Express on server-side, Nextjs(React) on client-side.
Problem:
When user spams clicking the LIKE button before the button re-render to UNLIKE, the express LIKE api could be fired multiple times causing the extra number to be put into "totalLike". For example, you clicked like 3 times very fast, there you get 3 totalLikes instead of 1. (noted: I choose to add totalLike to user to avoid too many nested populate when call in the future)
My Pseudo-code:
Simply +1 totalLikes when press like and -1 totalLikes when press unlike. And it should be just that !
router.patch(
'/like/:post',
(req, res, next) => {
// user_id = the_user_who_click_like_to:post
Post.updateOne(
// at this post, add the user_id LikedUser array, then ...
(res) => {
User.updateOne(
// at user_id, do { $inc: { totalLikes: 1 } }, <-- this is the problem
// because "totalLikes" could be plus more than once!
)})})
router.delete(
'/like/:post',
// Do the same but opposite, $pull user_id from Post and -1 totalLikes in User = face same problem as above
)
Now the questions:
What are the practical ways to avoid this from happening on
server-side?
Is blocking the client-side from firing normally done by only setting state to disabling React button ?
As a backend newbie, another improved approach for the shown Psuedo code would be eye candy.
There are of course different approaches you can use.
Usually people to like posts have to be logged in and thus have an account.
This enables you to store in the DB, attached to the user, the like.
When you get a request to like something you can just check if the user has liked that already or not and throw an error in case it's present.
Another way, of course not 100% safe (the first would be), is to use the browser's Memory Storage or send back a cookie.
You would again check if there is this cookie or not before processing the request.
Of course you would then add front-end code to show the like button as inactive if the user has liked it before or popup a login window if he is not logged in.
It's very hard to show a full functional code as it's a pretty big topic, but I hope these directives may help.

my code storage data in local storage on a website but when i navigate through the pages and register a new user the old user are deleted

var userInfo = [];
var myCostum;
//documentgetElementById("registerForm");
document.getElementById("registerForm").addEventListener("click", function ()
{
//var register = document.querySelector('#registerForm');
var name = document.querySelector('#fN').value;
var lastN = document.querySelector('#lN').value;
var userName = document.querySelector('#uN').value;
var passwrd = document.querySelector('#pS').value;
userInfo.push([name,lastN,userName,passwrd]);
localStorage.setItem("myCostum", JSON.stringify(userInfo));
});
I am using separate files for j, my website has a navigation bar with home,register,login,about me and shopping car. this code works fine if i register more than one user, i can see the users in the local storage on all pages and i can even sign in. the problem is when i go to register again and register a new user the users that i reister before are deleted and replaced by the new user. also if i go to home page i can an error (Uncaught TypeError: Cannot read property 'addEventListener' of null
at even-listener.js:9). i just do not had idea why register page seems to work but the rest not. I had another code using onclick in html but the same it does not give any error in any page but the users gone when i register new one after navigating through my pages. this is the first time using localStorage and i do not can i do or if it is normal. i am stack and i need to keep adding more code but i want to solve this problem first.
Lots of things going on here, but let me start from the basics.
1st never use local storage for sensitive information such as usernames and passwords. There's a lot of sites that copy local storages and send it to malicious people.
2nd you could in theory use session storage limited to the tab, but you still could be under the danger of xss.
3rd when the browser closes, all your data will be lost from the local storage anyway
As for your code. Your user info, should not be initiated as empty. You must get the previous value from local storage and push to it. Otherwise you are just overriding the previous value.
var userInfo = JSON.parse(localStorage.getItem('myCustom'));

How to pass variable into the Data.php in Magento?

So I am working on \app\code\core\Mage\Checkout\Helper\Data.php at the moment. And I am trying to call a variable but it doesn't seem It's working.
UPDATE 1
I have been able to pass the variable by method like this, but I need to declare the product ID manually, is there anything allows the method get the product id base on the product i added into cart?
$_productId = Mage::registry('current_product')->getId();
is not working in my case.
My test as below:
public function formatPrice($price)
{
$_productId = 463089; // need to call the current product by the enter the ID manually
$_product = Mage::getModel('catalog/product')->load($_productId);
$oldPrice = $_product->getFinalPrice(); //should be the original product price
return $this->getQuote()->getStore()->formatPrice($oldPrice);
}
The result after i refresh my page :
everything turns to 670
Many thanks
You're "working on \app\code\core\Mage\Checkout\Helper\Data.php", which is the first problem. Never edit the Magento core.
Assuming you move this to your own event observer to modify the data, you are loading the product ID with a static variable set to 463089, then doing nothing to calculate a new price, then displaying the products price.
From your code it makes perfect sense that the price would always remain the same since you are manually setting which product to pull the price from.
It could be a number of reasons why the quantity of the item is not changing the price. It might have something to do with other core edits you may have made.

Ember.js when using ModelFor('') in conjunction with the back button fails to load data

I am using Ember data and The RESTAdapter with an extension for Django.
Here is a JSBin
Here is how our routes are set up:
App.Router.map(function() {
this.resource('locations');
this.resource('location', {path:'locations/:location_id'}, function() {
this.resource('items', function() {
this.route('create');
});
this.resource('item', { path:'item/:item_id' }, function() {
this.route('edit');
});
});
});
App.LocationsRoute = Ember.Route.extend({
model: function () {
return this.get('store').find('location');
}
});
App.ItemsRoute = Ember.Route.extend({
model: function(){
//Get the model for the selected location and grab its item list.
//This will do a call to /locations/1/items
return this.modelFor('location').get('items');
}
});
Now this all works fine when we navigate to locations/1/items. The user is presented with a list of items relevant to the location with id 1.
When the user clicks one of these items it brings the url to #/locations/1/item/1 and displays the details of the item with id 1.
Now what doesnt work is this:
When I hit the back button the #/locations/1/items route loads but it does not have its data any more and no REST call to api/locations/1/items occurs. Even though the data displayed just fine when we first navigated to #/locations/1/items.
It is like Ember said "Well we already loaded that data, so we dont need to call the api again" but the data is somehow not being displayed in our template.
If I change the ItemsRoute model to this:
return this.get('store').find('item');
The scenario above works perfectly fine but the data is not based on our location.
Is there something I am missing with using this.modelFor? Or is my route set up incorrect?
Let me know if theres any extra info you need.
Update 1:
Having changed the model function to this I have discovered some new insights:
model: function(){
//Get the model for the selected location and grab its item list.
//This will do a call to /locations/1/items
var location = this.modelFor('location');
var items = location.get('items');
return items;
}
Upon first load of #/locations/1/items the location variable holds the location model and the items variable holds something which has a 'content' property, 'isFulfilled: true' and some other things.
This correctly works and displays the list of items. When i click on a particular item and got to #/locations/1/items/1 then hit the back button. The breakpoint triggers and location is still correctly populating with the location model.
However the items variable seems to just be a PromiseArray, do I need to somehow wait for the promise to be fulfilled before this model hook returns? I thought Ember already did this automatically? I suppose this means that the route is loading before the promise is fulfilled and thats why there is not data displayed?
Therefore my list is not populated correctly.
I'm on a phone, so I'll update this a bit later with more, but the problem is your location resource isn't a child of locations. Becaude of that, ember says why waste time fetching that route if it isn't a part of that resource path. It only hits the location route, which I'm betting you don't have a model hook for fetching the single location (at least based on the code above).
Ok, here is the deal. I have fixed the issue but have no idea why it fixed the issue.
Without further ado:
Here is a jsbin example of the exact setup I have. The only difference between the real one and the jsbin is the fact that I am using the RestAdapter instead of the FixtureAdapter. This is not technically true because I am using the ember-django-rest-adapter which extends the REST one.
The issue described in the question does not present itself in the jsbin but the exact setup with the ember-django-rest-adapter does present the issue.
The fix was to break the cyclic relationship between User -> Site -> Items -> User
For example if I comment out the 'locations' relationship in the User model, the back button works.
Or if I comment out the 'owner' relationship to User in the Item model the back button works.
I might ask a separate question to see what the reasoning behind the problem is, although if someone can shed any light in to why this is happening I'll happily accept the answer here.

Categories

Resources