I'm using ACF's update_sub_field function to add content from a loop to a child repeater field.
I've got it to a point where the data is being added to the child repeater but it's overwriting itself. It only ever updates the first row in the child repeater so I only ever see the last loop through.
I'm iterating the parent repeater using $counter, but when I try to add an iteration to the child repeater it breaks the function. Like so:
update_sub_field( array($field_key, $counter, $sub_field_key, $rowcount), $value, $post_id );
I've tried another function add_sub_row... this adds the correct number of rows to the child repeater's but doesn't add the data.
Here's my full code:
// Product Code Titles
$rows = $html->find('div[class=product-table]', 0)->find('tr');
$field_key = "field_5ae0882f9d6f9";
$sub_field_key = "field_5ae088999d6fb";
if(empty($rows)){
die("Empty array");
}
$titles = array(); // aka your $data
// here we fetch the first row and iterate to get titles
$row = current($rows);
foreach ($row->find('td') as $cell) {
$titles[] = array("column_title" => strip_tags($cell->innertext));
}
update_field( $field_key, $titles, $post_id );
// here we continue iteration starting from second row
$value = array();
$rowcount = 1;
while($row = next($rows)){
$cells = $row->find('td');
$columnsCount = count($cells);
$counter = 1;
foreach ($cells as $cell) {
$value[] = array("text" => strip_tags($cell->innertext));
update_sub_field( array($field_key, $counter, $sub_field_key), $value, $post_id );
echo '<pre>'; print_r($value); echo '</pre>';
$value = array();
$counter++;
}
$rowcount++;
}
Just to give some context, I'm recreating this table with the cell data being put into a child repeater field.
There's not much on this subject so hope this helps someone else.
I stopped it appending to the $value array, changed the function to update_sub_row and added a counter to iterate the child repeater rows.
Here's the full code:
// Product Code Titles
$rows = $html->find('div[class=product-table]', 0)->find('tr');
$field_key = "field_5ae0882f9d6f9";
$sub_field_key = "field_5ae088999d6fb";
if(empty($rows)){
die("Empty array");
}
$titles = array(); // aka your $data
// here we fetch the first row and iterate to get titles
$row = current($rows);
foreach ($row->find('td') as $cell) {
$titles[] = array("column_title" => strip_tags($cell->innertext));
}
update_field( $field_key, $titles, $post_id );
// here we continue iteration starting from second row
$value = array();
$rowcount = 1;
while($row = next($rows)){
$cells = $row->find('td');
$columnsCount = count($cells);
$counter = 1;
foreach ($cells as $cell) {
$value = array("field_5ae088b79d6fc" => strip_tags($cell->innertext));
update_sub_row( array($field_key, $counter, $sub_field_key), $rowcount, $value, $post_id );
echo '<pre>'; print_r($value); echo '</pre>';
$value = array();
$counter++;
}
$rowcount++;
}
Related
I have an array with products, filled by the API.
I want to extend it and add some values like categories, price. I tried to add & before the array when looping to use it by reference row. But when I added another while loop to add categories, the $row wasn't extended.
$products = array('id_product'=>12,'link'=>'test.html','description'=>'desc');
foreach($products as &$row) {
$row['price'] = 12;
$product = new Product($row['id_product'];
$categories = $product::getCategories();
$k = 1;
while ($cat = current($categories)){
$row['categoryid'.$k] = $cat['name'];
$k++;
}
}
$product::getCategories() return
array(1) { [0]=> array(1) { ["name"]=> string(8) "T-shirts" } }
The problem is that the array key with categoryid.$k is never created, I tried with foreach on categories but it didn't work.
In provided example in foreach loop $row will contains values 12, 'test.html' and 'desc'. So you can't use them as array.
Valid code:
$products = array();
$products[] = array('id_product'=>12,'link'=>'test.html','description'=>'desc');
Also you have invalid while loop, replace current function with array_shift, or use proper foreach loop
Edited:
Replace while with this code:
if (!empty($categories)) {
foreach ($categories as $key => $category) {
$row['categoryid' . $key] = $category['name'];
}
}
I fixed my problem by adding a function and pass by value the row parameter
private function addCategories(&$row){
$categories = $this->getProductCategoriesFull((int)$row['id_product']);
if (!empty($categories)) {
$k = 2;
foreach($categories as $category) {
if($k!= 2)
$row['categoryid' . ($k-1)] = $category['name'];
$k++;
if($k>5) exit;
}
}
}
And call it in the loop
$this->addCategories($row);
I have the following xml file:
row category="1" category_name="CatA" entry_id="1" entry_name="A1"
row category="1" category_name="CatA" entry_id="2" entry_name="A2"
row category="1" category_name="CatA" entry_id="3" entry_name="A3"
row category="2" category_name="CatB" entry_id="4" entry_name="B1"
row category="2" category_name="CatB" entry_id="5" entry_name="B2"
row category="2" category_name="CatB" entry_id="6" entry_name="B3"
row category="3" category_name="CatC" entry_id="7" entry_name="C1"
row category="4" category_name="CatD" entry_id="8" entry_name="D1"
and I want to produce below html:
CatA
----A1
----A2
----A3
CatB
----B1
----B2
----B3
CatC
----C1
CatD
----D1
for this I am using below php xml parser:
$ndeshjet=simplexml_load_file("xml_file.xml");
$new_category = 1;
foreach ($ndeshjet->row as $entry) {
$category = $entry['category'];
if ($category <> $new_category){
$category_name = $entry['category_name'];
echo $category_name."</br>";
$new_category = $category;
} else {
$entry_name = $entry['entry_name'];
echo "----".$entry_name."</br>";
}
}
?>
but the result is :
----A1
----A2
----A3
CatB
CatB
CatB
CatC
CatD
Thanks in advance
As an alternative, you could gather all the values first inside an array and make the category name as key pushing same keys inside. After thats done and gathered, print them accordingly:
$categories = array();
// gather inside container
foreach ($ndeshjet->row as $entry) {
$category_name = (string) $entry->attributes()->category_name;
$entry_name = (string) $entry->attributes()->entry_name;
$categories[$category_name][] = $entry_name;
}
// presentation
foreach($categories as $category_name => $entries) {
echo $category_name . '<br/>';
foreach($entries as $entry) {
echo '----' . $entry . '<br/>';
}
}
Sample Output
this code get table.
I want to remove first and second tr tag in the table.
$data = array();
$table_rows = $xpath->query('//table[#class="adminlist"]/tr');
if($table_rows->length <= 0) { // exit if not found
echo 'no table rows found';
exit;
}
foreach($table_rows as $tr) { // foreach row
$row = $tr->childNodes;
if($row->item(0)->tagName != 'tblhead') { // avoid headers
$data[] = array(
'Name' =>trim($row->item(0)->nodeValue),
'LivePrice' => trim($row->item(2)->nodeValue),
'Change'=> trim($row->item(4)->nodeValue),
'Lowest'=> trim($row->item(6)->nodeValue),
'Topest'=> trim($row->item(8)->nodeValue),
'Time'=> trim($row->item(10)->nodeValue),
);
}
}
and question 2
In the bellow table tr have two class --- EvenRow_Print and OddRow_Print ---
$data = array();
$table_rows = $xpath->query('//table/tr');
if($table_rows->length <= 0) {
echo 'no table rows found';
exit;
}
foreach($table_rows as $tr) { // foreach row
$row = $tr->childNodes;
if($row->item(0)->tagName != 'tblhead') { // avoid headers
$data[] = array(
'Name' =>trim($row->item(0)->nodeValue),
'LivePrice' => trim($row->item(2)->nodeValue),
'Change'=> trim($row->item(4)->nodeValue),
'Lowest'=> trim($row->item(6)->nodeValue),
'Topest'=> trim($row->item(8)->nodeValue),
'Time'=> trim($row->item(10)->nodeValue),
);
}
}
How can I echo both tr in one 2d array .
examp.
Array(
[0] => Array(
//array
)
}
Thank's
For question 1 - there are different ways to skip the first and last element, e.g. removing the first entry using array_shift() and the last entry using array_pop(). But as it's not clear if it'd be better to keep the array as it is, it's possible to skip both entries in the foreach in an easy way like using a counter, continuing for the first entry and breaking for the last:
$i = 0;
$trlength = count($table_rows);
foreach( ...) {
if ($i == 0) // is true for the first entry
{
$i++; // increment counter
continue; // continue with next entry
}
else if ($i == $trlength - 1) // last entry, -1 because $i starts from 0
{
break; // exit foreach loop
}
.... // handle all other entries
$i++; // increment counter in foreach loop
}
I have a CSV file with a header row. The code puts the column names as the $Key and $postion is the values. This works okay.
This is the loop creating the string of attributes to add to the product. When i "echo $sets" it displays correctly
foreach ($each_csv as $position => $details) {
$sets .= ->set$position('$details')}
$sets is creating the ->set code for the product. How do I implement the loop values into the product set function
$product->setWebsiteIds(array(1))
->setTypeId('simple')
->setMediaGallery (array('images'=>array (), 'values'=>array ()))
// How can I add the looped values here from the array
. Full Code Below
<?php
include ("../config/init.php");
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product');
$rows = array_map('str_getcsv', file('prouduct_ids.csv'));
$header = array_shift($rows);
$csv = array();
foreach ($rows as $row) {
$csv[] = array_combine($header, $row);
}
//print_r($csv);
reset($csv);
$dataSetCount = count($csv);
echo "<h1>There are $dataSetCount products</h1>";
$i = 0;
foreach ($csv as $each_csv) {
$i++;
echo "<h2>csv $i</h2>";
if(!$product->getIdBySku($each_csv['Sku'])){
echo $each_csv['Sku'] . " - Already in website";
} else {
foreach ($each_csv as $position => $details) {
$sets .=->set$position('$details')}
$product->setWebsiteIds(array(1)) //website ID the product is assigned to, as an array
->setTypeId('simple') //product type
->setMediaGallery (array('images'=>array (), 'values'=>array ()));
//media gallery initialization
$product->save();
unset($sets);
}
}
You want to use the $product->setData('data_key', 'value') function.
For example, this function:
$product->setTypeId('simple')
Is the exact same as this function:
$product->setData('type_id', 'simple')
Keep in mind that a capital letter represents an underscore in the attribute name. typeId is type_id because the I in Id is capitalized.
The code in your functon will look like this:
[...]
foreach ($each_csv as $position => $details) {
$sets .= $product->setData($position, $details)
[...]
Where $position is the attribute code, and $details is the attribute value.
I'm using simple_html_dom_helper so do some screen scraping and am encountering some errors.
The second foreach runs 4 times (since sizeof($pages) == 4), while it should only run once. I got this code from an example script where table.result-liste occurs several times on the page. In my case it only occurs once, so imho there is no need for a foreach. The print_r($data) prints out the same thing 4 times and there's no need for that.
Further down I'm trying to do the same without the foreach but it just prints out no, so there seems to a different response and am not sure why.
foreach( $pages as $page )
{
$p = $this->create_url($codes[0], $price, $page); //pass page number along
$p_html = file_get_html($p);
$row = $p_html->find("table[class=result-liste] tr");
//RUNS OK BUT NO NEED TO DO IT FOUR TIMES.
//CLASS RESULT-LISTE ONLY OCCURS ONCE ANYWAY
foreach( $p_html->find("table[class=result-liste] tr") as $row)
{
//grab only rows where there is a link
if( $row->find('td a') )
{
$d_price = $this->get_price($row->first_child());
$d_propid = $this->get_prop_id($row->outertext);
$data = array(
"price" => $d_price,
"prop_id" => $d_propid
);
print_r($data);
}
}
//MY ATTEMPT TO AVOID THE SECOND FOREACH DOES NOT WORK ...
$row = $p_html->find("table[class=result-liste] tr");
if( is_object($row) && $row->find('td a')) print "yes ";
else print "no ";
}
Even though the table[class=result-liste] only occurs once on your page, this find statement is looking for the <tr> elements that are the table's rows. So unless your table has only one row, you will need this foreach.
$p_html->find("table[class=result-liste] tr")
Your code
foreach( $p_html->find("table[class=result-liste] tr") as $row)
{
//grab only rows where there is a link
if( $row->find('td a') )
{
$d_price = $this->get_price($row->first_child());
$d_propid = $this->get_prop_id($row->outertext);
$data = array(
"price" => $d_price,
"prop_id" => $d_propid
);
print_r($data);
}
}
Replace above code by MY code
$asRow = $p_html->find("table[class=result-liste] tr");
$row = $asRow[0];
//grab only rows where there is a link
if( $row->find('td a') )
{
$d_price = $this->get_price($row->first_child());
$d_propid = $this->get_prop_id($row->outertext);
$data = array(
"price" => $d_price,
"prop_id" => $d_propid
);
print_r($data);
}
Try with this.