So I've been dealing with this problem for quite some time and can't find a clear solution. So basically I'm adding new products directly into db using Product object. For now it went well but I can't manage to link new products with a category.
$cat_ids = [];
foreach ($value['kat_naziv'] as $cat_val) {
$cat_ids[] = (int)$luceed->selectCategoryIds($cat_val)[$cat_val]['id_category'];
}
$product->id_category = 3;
$product->id_category_default = 3;
$product->save();
$product->addToCategories($cat_ids);
So basically $cat_ids is an array of integers that i'm getting from db where name is something i pass as a parameter to selectCategoryIds;
What is the problem here why it wont associate newly created product with categories i give to it
After creating your new product ( i.e $product = new Product() ). You can assign categories to product using.
$product->updateCategories($category_array);
where
$category_array = array("0" => "2", "1" => "3", "4" => "6"...... );
#FMEModule That's exactly what i did there but i've filled the array with the id's of categories from the database
Anyways I ended up writing my own queries for associatting products with categories
Version (1.6)
I found the following bug in Product.php, in addToCategories, search for if (!in_array($new_id_categ, $current_categories)) (line 964),
notice that the if is missing {} - add them, and the problem is solved:
foreach ($categories as $new_id_categ) {
if (!in_array($new_id_categ, $current_categories)) {
if ($position == null) {
$position = (int)$new_categ_pos[$new_id_categ];
}
$product_cats[] = array(
'id_category' => (int)$new_id_categ,
'id_product' => (int)$this->id,
'position' => $position,
);
}
}
Prestashop developer LOVEs omitting {} after if and foreach - this is supper annoying and bug prone.
This issue is fixed in the repo:
https://github.com/PrestaShop/PrestaShop/blob/1.6.1.x/classes/Product.php
NOTE: this solution solves the bug in the following scenario - a product that is already link to a category is link to another category (while keeping the original category)
although I'm not sure if this is the scenario in the question.
Related
I switched over to Opencart 3.0.. Not to fond of the .tpl to .twig changes.
Anyways, I have been trying, to no avail, to display all products from a particular category on another category page.
I found this foreach loop:
{% for product in products %}
Which I imagine reads
<?php foreach ($products as $product) { //do something } ?>
I tried adding the Loop to the path:
catalog/view/theme/*/template/product/category.twig
but it only shows the products from the current category page id I am currently on.
Any help would be greatly appreciated.
It's generally bad practise on OC to edit the files directly, rather look at OCMOD or VQMOD to make runtime changes but not edit the core file. Granted this may be an additional complication right now.
If you look at the category.php file in the /catalog/controller/product/ folder around line 150, you'll see these lines of code:
$data['products'] = array();
$filter_data = array(
'filter_category_id' => $category_id,
'filter_filter' => $filter,
'sort' => $sort,
'order' => $order,
'start' => ($page - 1) * $limit,
'limit' => $limit
);
$product_total = $this->model_catalog_product->getTotalProducts($filter_data);
$results = $this->model_catalog_product->getProducts($filter_data);
What you need to do is create a new $filter_data variable with your requisite filters, you can just have the category ID if that's all you need.
Look at the line below:
$results = $this->model_catalog_product->getProducts($filter_data);
It's calling the method getProducts which is located in the model CatalogCategory (/catalog/model/product.php) this method will build a SQL query based on the filters passed to the method and return an associative array with the results (hence the aptly named $results variable).
The controller file we first looked at then iterates through these $results and stores the values in $data['products'].
Putting this together, you can try the following:
$data['products2'] = array();
$new_filter_data = array(
'filter_category_id' => 13 // or any relevant ID
);
$results2 = $this->model_catalog_product->getProducts($new_filter_data);
This isn't a complete solution as the controller file continues to resize images, get reviews etc. So you'll need to adjust this according to what your needs are and play around a little.
Just make sure you're working on a local copy of the site!
Not sure how to title this properly but here's the issue I am running into currently. I built a cart and checkout system and it loads all the data into a database when it finalized the order. To save some space, I stored just the item IDs originally but then I ran into the issue of if I deleted the item from the database (because it was discontinued or whatever) then it wouldn't return the info I needed. And if they ordered more then 1 item the database record would be wrong. So I stored the data like so:
Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2
OR
1:3:20.00:Flower Hat, 2:1:17.75:diamonds
The issue I have right now that I need help with is this. I need to seperate the four values into variables like $price, $item, $id, $ammount so I can display them on the order history page and I need to loop through all items on the array so I can print a row for each item with all four fields respective to that item.
I use strpos already to get the shipping info from the same database field which is formatted as METHOD:Price but since I have 3 :'s on my string I'm not sure how to go through each one. Thanks.
Here's a function
function parseItems($dbjunk){
$cart = array();
$items = explode(",",$dbjunk);
foreach($items as $i){
$chunks = explode(":", $i);
$cart[] = array(
"ItemID" => $chunks[0] ,
"Quantity" => $chunks[1] ,
"Price" => $chunks[2] ,
"name" => $chunks[3]
);
}
return $cart;
}
Example usage:
$dbjunk = "Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2";
$parsed = parseItems($dbjunk);
print_r($parsed);
See: https://3v4l.org/rBkXF
If you need variables instead of an array you can use list(), like this..
$dbjunk = "Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2";
$parsed = parseItems($dbjunk);
foreach($parsed as $p){
list($itemID, $Quantity, $Price, $name) = array_values($p);
var_dump($itemID, $Quantity, $Price, $name);
}
see: https://3v4l.org/l4vsn
You should not physically delete items from your database. Instead, put a new column named 'is_active' or something like that to indicate whether the product is active/non-deleted.
Answering your question, here is my suggestion:
$orderString = '1:3:20.00:Flower Hat, 2:1:17.75:diamonds';
$items = array();
foreach(explode(', ', $orderString) as $itemString) {
$itemData = explode(':', $itemString);
$items[] = array(
'id' => $itemData[0],
'amount' => $itemData[1],
'value' => $itemData[2],
'description' => $itemData[3]
);
}
with this code, you will obtain an array with the data of all the items in the string, no matter how much items are in the string
try something like
$data = 1:3:20.00:Flower Hat, 2:1:17.75:diamonds
list($price, $item, $uid, $id, $ammount) = explode(":", $data);
echo $user;
echo $item;
Read about First Normal Form. Basically, you want to store one value in one field. So, instead of this:
shipping = "method:price"
You want something like this:
shipping_method = "method"
shipping_price = "price"
Don't concern yourself with space -- it's essentially free nowadays.
Regarding your deleted items dilemma, your initial implementation was the way to go:
I stored just the item IDs originally
In addition to reverting to this technique, I would recommend two things:
Add a boolean field to your item table to represent if the item is currently available or not. This gives you the additional feature of being able to toggle items on/off without having to delete/insert records and change ids.
Before deleting an item, check to see if it's ever been ordered. If not, it's ok to delete. If so, instead just deactivate it.
I've build a module to make a custom page with some products. I've tried to
//get all products
$products_partial = Product::getProducts($this->context->language->id, 0, 1000, 'name', 'asc');
$products = Product::getProductsProperties($this->context->language->id, $products_partial);
foreach ($products as $product)
{
//here comes some logic to select some products (not relevant for this question)
//echo the image ID
$results[] = $product;
}
$this->context->smarty->assign(array(
'products' => $results
));
//this is a copy of themes/default/product-list.tpl
$this->setTemplate("product-list.tpl");
Now all products are shown, but without the right image. It turns out that $product['id_image'] is set to 'en_default', but I don't know why. But why?
I've tried to search for the problem on the PrestaShop forums, and I found people with the same problem (1, 2), but there was no solution given.
Look at a function, that sets the en_default and I think it is clear, why it does, what it does.
public static function defineProductImage($row, $id_lang)
{
if (isset($row['id_image']))
if ($row['id_image'])
return $row['id_product'].'-'.$row['id_image'];
return Language::getIsoById((int)$id_lang).'-default';
}
This is from 1.5 version.
I am trying to reorganize a PHP array (on a WordPress page). My site was coded by someone else, and I'm trying to make things better. I think they did things in a confusing way (poor use of the categories). Rather than recode the entire site, I wanted to see if someone could help me work around a fix.
So, basically, I have an array inside an array. A list of categories, and each category has specific details. I'm calling the categories, based on it's parent. I need to reorganize the list/array of categories, so they can print out in the order that I need them to.
$cat_tree = get_category_parents(wt_get_category_ID(), FALSE, ':', TRUE);
$top_cat = split(':',$cat_tree);
$parent = $top_cat[0];
$idObj = get_category_by_slug($parent);
$args = array(
'child_of' => $idObj->term_id,
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => 0);
$counter_c=1;
$categories = get_categories( $args );
if($counter_c == 1) $counter_c = '';
foreach ($categories as $category) {
?>
<div> this is where each category array info gets printed... information goes:<br />
Name: <?=$category->cat_name ?> (<?=$category->cat_ID ?>)
</div>
<?php if($counter_c == '') $counter_c = 1; $counter_c++; } // Reset Query
wp_reset_query();
?>
On one page, $cat_tree outputs "entertainment:actors:".
$parent or $topcat[0] outputs "entertainment"
$topcat[1] outputs "actors"
When the "foreach" runs, I get an list sorted by the ID ...
Actors (13)
Artists (14)
Directors (25)
Writers (26)
DeeJays (35)
I need to reorganize this list into a specific order. Each page is different. So I may have to reorganize a list differently for each page. I may need...
Writers (26)
Actors (13)
DeeJays (35)
Artists (14)
Directors (25)
So, I need a way to do this. I thought that maybe I could say "if" on the "actor page", slide "Writers" to the end of the array (I know there is some way to do this), then slide Actors to the end, then DeeJays, then Artists, then Directors. Then run the foreach.
Or, if page is something else, I can slide other elements to the end of the array. That seems a bit much, but it's the only work around that I could think of. Of course, my php knowledge is limited, so any help is appreciated.
You could try a custom sort:
$order = array('Writers', 'Actors', 'DeeJays', 'Artists', 'Directors');
function catsort($a, $b) {
global $order;
$ak = array_search($a->cat_name, $order);
$bk = array_search($b->cat_name, $order);
if($ak === false) $ak = 0;
if($bk === false) $bk = 0;
return $ak - $bk;
}
usort($categories, 'catsort');
Each page would just need a different order array.
i want to filter and paginate a product collection. everything is fine - except pagination. im just getting the whole collection back, instead of 3 items for the first page.
//fetch all visible products
$product_collection = Mage::getModel('catalog/product')->getCollection();
//set wanted fields (nescessary for filter)
$product_collection->addAttributeToSelect('name');
$product_collection->addAttributeToSelect('description');
$product_collection->addAttributeToSelect('price');
$product_collection->addAttributeToFilter('visibility', array('neq' => 1));
//filter by name or description
$product_collection->addFieldToFilter(array(
array('attribute'=>'name','like'=>$sTerm),
array('attribute'=>'description','like'=>$sTerm)
));
//filter for max price
foreach ($product_collection as $key => $item) {
if($item->getPrice() >= $priceTo){
$product_collection->removeItemByKey($key);
}
}
//pagination (THIS DOESNT WORK!)
$product_collection->setPageSize(3)->setCurPage(1);
//TEST OUTPUT
foreach ($product_collection as $product) {
echo $product->getName().'<br />';
}
thanks for your support!
You are so close! Try moving that $product_collection->setPageSize(3)->setCurPage(1); line before the first foreach() iteration over the collection.
Magento collections are lazy-loaded. Until you directly load() them (or implicitly load them via a call to count() or foreach()) you can modify the collection properties which affect the underlying query (EDIT: see note below). Once the collection has been loaded explicitly or implicitly though you will only get the members of the _items property that have been set.
FYI you can call clear() to leave the original query-affecting properties (filters, sorters, limits, joins, etc) in place and then add further properties.
HTH
EDIT: Actually, adjusting query properties is always possible regardless of _items load state, but the effect won't be visible until the collection is regenerated.
Thanks #Ben! You gave me the right hint. Now it does work! Basically I'm creating another collection and filter this one by the ids of the already filtered items. Afterwards its easy to add pagination to that new collection. That's the working code:
//fetch all visible products
$product_collection = Mage::getModel('catalog/product')->getCollection();
//set wanted fields (nescessary for filter)
$product_collection->addAttributeToSelect('name');
$product_collection->addAttributeToSelect('description');
$product_collection->addAttributeToSelect('price');
$product_collection->addAttributeToFilter('visibility', array('neq' => 1));
//filter by name or description
$product_collection->addFieldToFilter(array(
array('attribute'=>'name','like'=>$sTerm),
array('attribute'=>'description','like'=>$sTerm)
));
//filter for max price
foreach ($product_collection as $key => $item) {
if($item->getPrice() >= $priceTo){
$product_collection->removeItemByKey($key);
}
}
//build id array out of filtered items (NEW!)
foreach($product_collection as $item){
$arrProductIds[]=$item->getId();
}
//recreate collection out of product ids (NEW)
$product_filtered_collection = Mage::getModel('catalog/product')->getCollection();
$product_filtered_collection->addAttributeToFilter('entity_id', array('in'=>$arrProductIds));
//add pagination (on new collection) (NEW)
$product_filtered_collection->setPageSize(3)->setCurPage(1);
//TEST OUTPUT
foreach ($product_filtered_collection as $product) {
echo $product->getName().'<br />';
}