I have created two Custom Post Types using JetEngine:
Place
Product
I have also enabled the JetReviews for the Place CPT. So, each Place can have multiple Products, and each Product can have multiple reviews.
I want to display the Place rating average based on their Product ratings. For instance: Product 1 has three reviews, the first one has 2 stars, the second one has 5 stars and the third one has 1 star. Therefore, the Product 1 rating is "2,66" stars.
Since I wasn't able to find a graphical solution to achieve this, I have created an SQL query using JetEngine QueryBuilder:
SELECT AVG({prefix}jet_reviews.rating)
FROM {prefix}jet_reviews
INNER JOIN {prefix}posts
ON {prefix}posts.id = {prefix}jet_reviews.post_id
INNER JOIN {prefix}jet_rel_default
ON {prefix}jet_rel_default.child_object_id = {prefix}posts.id
WHERE {prefix}jet_rel_default.parent_object_id = "{current_id}";
But here I didn't know how refer to the Place ID when viewing the Single Post, So I guessed it could be the same as the {prefix} (but this didn't work).
I have tried asking this on Crocoblock FB Community and its subreddit a while ago but hadn't been answered.
Does anyone know how to display the Product's average rating in each Place Single Post like I "explained" before?
Related
Using wordpress for a client (I wouldn't over wise).
On their home page I want to get the latest 4 posts for each of 4 different categories, I then want to get 3 additional posts that are latest from any category and not currently used above, followed by 5 with the greatest number of page views in the last 2 weeks.
All this is easy but to use wordpress get_posts would require 6 different calls to the database, can this be done with one instead?
The Procedure:
Get 4 latest posts from the category NEWS
Get 4 latests posts from the category POLITICS that were not already fetched from the first four (there is a possibility that posts are in both categories)
Get 4 latest posts from category FEATURES that were not already fetched
Get 4 latest posts from category COMMENT ... etc..
Get the 3 latest posts from any category that were not yet fetched
Get 5 posts with the greatest number of page views (stored in meta data under the name meta-page-views) that were not yet fetched
Is this possible without multiple queries.
Thanks,
There is no way to do this in one call with usual wordpress functions. It might be possible with different categories in one query but you can't have different sorting orders in one query.
If you really really have to use one query, you could pull for example the latest 100 posts, store them in an array and then use PHP to sort and filter the result to your categories. However, this won't work well with the page views. Also, a category that hasn't been posted within the last 100 posts wouldn't appear on your page.
I don't see a point in using one query only since it only creates problems. Even the most popular wordpress themes don't do that.
If your client is concerned about server load you should probably talk to them about caching.
I am about to build a web shop and need to come up with a solution of tracking user information, and based upon that suggest the users products they may like too and so build an individual user profile (what they like).
Information to be tracked/used for the algorithm, I thought should include:
past orders
wish list/bookmarks/favourites...
search terms entered
products viewed (and here also track and consider the "drop-off"-quote, meaning wether a user closes the site/goes back immediately or looks at more pictures/scrolls down (viewport) etc)
Products are assigned to categories as well as different attributes such as colors, tags etc. The table product has relations with color, category, etc.
product
id_product
price
timestamp_added
color
id_color
...
product_color
id_product_color
id_product
id_color
The questions are:
1) How would you structure a database to track e.g. products viewed? Should it be just like this?:
product_viewed
id_product_viewed
id_product
id_user
timestamp
2) If I want to calculate e.g. the users top 3 favourite colors based on colors of products the user bought, put on their wish list, bookmarked, viewed: can it be handled from a performance point of view to calculate which products should be recommended to this when querying the database every single time? Or do you update a user profile from time to time, storing only the already calculated favourite color at the moment based upon the tracked data and use the stored calculated data to find products that match this information?
How do big sites like facebook, amazon or pinterest do this? On pinterest you get suggestions for items you may like based on what items you clicked on before. How do they handle this?
Yes, your schema for product_viewed is OK.
As for their three favorite colors, try this untested code:
select c.name, count(*) as rank
from product_viewed pv
JOIN product_color pc on pc.id_product = pv.id_product
JOIN color c on pc.id_color = c.id_color
where pv.id_user = 1
group by c.name
order by rank desc
limit 3
Given indexes on the ids used to join the tables and a reasonable limit on the number of items viewed, this should have decent performance. Down the road, you might only look at their most recent 100 products, etc., just to keep it from growing forever. (Or, as you suggest, caching).
There's no magic to this, so it's probably similar to that those other sites are doing.
Doing it with tables like you just wrote is a good way.
Facebook and etc. is doing it that way as well.
But for more efficiency, they use so called B-Trees.
I have a system in which I have to select "similar" records. Imagine a database containing a big list of products and when the user enters partial name of a product, a list of products come up as suggestions about the product he is searching for. These products have a longer description field too.
This is NOT about a WHERE product_name LIKE '%entered_string%' query, I think. The logic is akin to the one Stack Overflow might use, id est: when you ask a question, it prompts you with Questions that may already have your answer and Similar questions, both obviously using a method to derive what I want to ask from my question title/content and search against the database, showing the results.
I just wonder whether it is accomplishable with PHP and using MySQL as the database.
Example:
Entering food should give us results like 1kg oranges, bread and cookies. Both of these would have something similar which could help to link them programmatically to each other.
There can lots of methods to approach this scenario. but I think straight one is to have multiple keywords/tags mapped with every item. so when user types in, you would not be searching item table, you should be searching the mapped keywords and based on that searching loading the relevant items.
If you want similar products to show up, you need to put that information in your database.
So, make a category for foods, and assign every food product to that category. That way you can select similar products easily. There is no other efficient way to do this
So your database:
categories:
|id|name
1 fruit
2 Cars
Products
|id|name|category_id
1 apple 1
2 Ford focus 2
And you can select like this:
SELECT `name`,`id` FROM `products` WHERE category_id = 1;
Another way (as suggested in a comment) are tags
Products
|id|name|tags
1 apple "fruit food delicious"
2 Ford focus "Car wheels bumper"
Best way is to use a fulltext search on the tags:
SELECT * FROM `products` WHERE MATCH(tags) AGAINST ('fruit')
Make sure to have a fulltext index on tags.
I'm really hoping someone can help me with this. I have a number of product attribute types that users can select from to refine the products that are returned to them on screen. What I'm trying to do is, for each product attribute type, I want to list all attributes that relate to either the selected category or search term, then once they've made their selections, I still want to display each of the attributes that relate to the category or search term, but only display a clickable link if the product count for that particular attribute is greater than 1 and for those that have a product count of zero, I want to list them, but make them unclickable. An example of what I'm trying to achieve can be found on the ASOS website, in the left hand menu
http://www.asos.com/Women/Dresses/Cat/pgecategory.aspx?cid=8799#state=Rf961%3D3340%2C3341%40Rf-200%3D20&parentID=Rf-300&pge=0&pgeSize=20&sort=-1
Initially I tried using just joins to achieve this, but I wasn't able to do it, successfully. So I decided to create a temporary table for each attribute type which held a list of all the attributes that related to the main query and then created a refined query, with a left join. Here's my code:
CREATE TEMPORARY TABLE temp_table
SELECT su_types.id, type AS item FROM su_types
INNER JOIN su_typerefs ON su_types.id=su_typerefs.id
INNER JOIN su_pref ON su_typerefs.mykey = su_pref.mykey
WHERE wp_category_id =40 GROUP BY su_typerefs.id
$sudb->query($query);
if ($sudb->affected_rows > 0) {
SELECT temp_table.id,item,COUNT(su_typerefs.mykey) AS product_count FROM temp_table
LEFT JOIN su_typerefs ON temp_table.id=su_typerefs.id
LEFT JOIN su_pref ON su_typerefs.mykey = su_pref.mykey
LEFT JOIN su_stylerefs ON su_pref.mykey = su_stylerefs.mykey
LEFT JOIN su_productrefs ON su_pref.mykey = su_productrefs.mykey
WHERE wp_category_id =40 AND su_stylerefs.id in (91) AND su_productrefs.id in (54) AND su_typerefs.id in (159) GROUP BY su_typerefs.id
if ($itemresults = $sudb->query($query)) {
while($itemresult = $itemresults->fetch_array(MYSQLI_ASSOC)) {
$id=$itemresult['id'];
$item=$itemresult['item'];
$product_count=$itemresult['product_count'];
build_link($list_type, $item, $product_count, $id);
}
}
In the above example the first query selects all the product types that relate to a particular category, say dresses. And the second query is based on the refinements the user has made on the category, in this example this is product, product type and style. A user can also refine their search by colour, fit, fabric and design.
There are a couple of issues with this:
1) The number of results returned in the second query do not match the results of the first. Using the above as an example, I wish to list all products that relate to the chosen category, then using the second query return the product count for each of these products as I described above. So if the temporary table returns, trousers, jeans and skirts. I expected these three items to be displayed on screen based on the conditions applied in the second query, however my results may only show trousers and jeans, if there is not a match for skirts in the second query. I thought that using a left join would mean that all the results of the temporary table would be displayed.
2)Also I wonder if I'm doing this the most efficient way. I have a total of 8 attribute groups, and therefore need to do the above 8 times. If the user choses to refine the results using all 8 attribute groups then in addition to the temp table join, there will be a total of 9 joins for each type. It's taking a while to execute, is there a better way to do this? There are approximately 1/2 million products in the table, and this will probably be 5 times this, once my site goes live.
I really hope all that I have written makes sense and I'd really appreciate the stackoverflow community's help with this, if anyone can help. I apologise for the essay ;). Thanks in advance
To answer your first question; yes, a LEFT JOIN will indeed keep all data from the initial table. That, however, isn't the problem.
The reason why you lose empty categories, is most likely (I say this because I don't fully know your db structure) because of the where condition filtering out all results based on the data in the joined tables.
If for a category all items get filtered out (possibly including the NULL joined values), you will not get this category back from that query anymore. Also the GROUP BY is done on a joined column, that might also effectively wipe out your other categories.
As for the second question, you already state it's taking long; so it's probably not the way to go if you want things to work fast ;) (okay, obvious answer, low hanging fruit, etc). What you might want to do, is get a collection of keys from the filterable categories first, and use that data to select items.
This prevents that you have to join up your entire products table in a temp table (at least, that's what I think you're doing), which of course will take long with the given number of entries. Selecting a list of matching IDs from the given attributes also gives you the advance of using your indexes (more), which a temp-table probably won't have. If this is possible and feasible mainly depends on your schema's structure; but I hope it might lead you to the direction you want to go :)
Really hope someone can help me or at least point me in the right direction. I working on a product site, that allows visitors to filter their results using a menu on side of the product results, similar to what www.asos.com have done. Basically, they can chose product type, style,price,fit ... etc. Each of these fiter types, have their own table and a reference table which links each value to the products table. EG There is a
Products table with productkey and all other product information
Colours table, with the following fields, Colour_ID, Name
Colourref table with productkey, Colour_ID
I'm using MySQL and PHP. I know how to query the database and display the data if the visitor makes one selection from each filter type and then to display the counts for each attribute, but I'd really like to be able to allow them to make multiple selections and then calculate the counts for each attribute, based on what's been selected. I've looked into how this should be done, and I've seen that subqueries are an option, but I'm concerned about how many subqueries I would need to create as I have 9 filter groups, that can have a large number of values. There are currently, 1/2 million products in the database, and this grow over time. I'm capturing the values that need to be queried via the url, so as an example
page=1&view=20&product=125,137,147&type=1,3,5&colour=3,9,5&material=187,345
As you can see from the example, I can have multiple values for each time. I tried writing a query using AND. Example, product = 125 AND product = 137, but that doesn't work.
Does anyone have any advice on the best way to go about doing this even if it's just a point in the right direction?
Any help will be greatly appreciated
Thank you in Advance
Vivien
Basically you answered your own question already:
SELECT ...
FROM ...
WHERE (product = 125 OR product = 137) AND
(colour = 3 OR colour = 8 OR colour = 5) ...
You need to use OR instead of AND if you want to select several products, colours and so on.
If you want both a product and colour then you need to combine those using AND in between. There is no need for subqueries here.
It's easier to use IN though:
SELECT ...
FROM ...
WHERE product IN (125, 137, 147) AND colour IN (3, 5, 8)
A more complete example of this SQL code:
SELECT p.*
FROM Products p
LEFT JOIN Colourref cr
ON cr.productkey = p.productkey
LEFT JOIN Colours c
ON c.Colour_ID = cr.Colour_ID
WHERE
p.productkey IN (1, 2, 4)
AND c.Colour_ID IN (1, 2)
This will select all products that have the ID 1, 2 or 4 which have the colours 1 or 2.
It left joins the required tables on the IDs and then filters the desired values.