Woocommerce Order / AFC get_sub_field / get_sub_field_object (array) - php

Have setup ACF repeater field that stores various amount of tracking numbers in the order. Having 0 success with retrieving this information so need some advice.
Am using this to put information in subfields and it does the job
foreach ($base->DocumentLines->DocumentLine as $item) {
foreach ($item->MiscData as $misc) {
foreach ($misc->PackageNo as $package) {
$trackno = (string)$package->TrackingNo;
update_post_meta("$order_id", $field_rep, $count);
$sub = $count +1;
update_sub_field(array($field_key_rep, $sub, $field_key_sub), $trackno, "$order_id");
$count = $count + 1;
update_field($field_key, $trackno, "$order_id");
}
}
}
This works well, but then i need to retrieve this numbers and write em out. They are getting included in an email so need to retrieve the data outside of order.
Before rebuilding the function to be able to handle multiple numbers i did use a single field and could retrieve the information with
get_post_meta($order_id, 'tracking', true);
Feels like i have been trying everything now but got absolutely nothing.
Image from one of the orders, in this one it’s 10 tracking numbers but it varies from 1 to 20 if it's to any help.

The feeling when you realize after 10 hours that your missed a capital letter in sub field name.
Just wanted to submit my solution and hopefully it can help someone else having issues with ACF Repeater fields + Woocommerce
For my specific case i did make a function that could extract all the tracking numbers my function above did add from XML files.
$function trackingNo($postID) {
$field_rep = 'trackingNo';
$field_sub = 'no';
if (have_rows($field_rep, $postID)) {
$trackingNo = array();
// loop through the rows of data
while (have_rows($field_rep, $postID)):
the_row();
// Add to array
$trackingNo[] = get_sub_field($field_sub);
endwhile;
$foo = implode('&consignmentId=', $trackingNo);
$bar = 'urlzz/tracktrace/TrackConsignments_do.jsp?&consignmentId=';
$value = $bar . $foo;
return $value;
}
}
Any advice for improvement is always welcome, my PHP is so'n'so :)

Related

PHP - Output array value that contains a specific text marker

I'm using a function to output a collection of products in Shopify, onto a WordPress page.
I've got most of the data displaying correctly, except a custom value that is entered as a tag in Shopify. Using the api, I'm then trying to get this specific tag for the product subtitle which is formatted with att:Subtitle: before each product custom value/text.
This is the code I have got to (I've commented other unsuccessful attempts in the middle) - this is inside the overall code to show the 4 products in the Shopify collection:
// Using tags to output custom data from products
$tags = $current_product['tags'];
// $tags is a string, this turns the values into an array
$product_tags = explode(',', $tags);
// Evaluate if there is a string with att:Subtitle in the product tags
// https://tecadmin.net/check-string-contains-substring-in-php/
$subtitle_attribute_key = "att:Subtitle:";
if (strpos($tags, 'att:Subtitle:') !== false) {
// Returns a numbered value corresponding to my subtitle attribute
// $key = array_search($subtitle_attribute_key, $product_tags);
$sub = strpos($tags, $subtitle_attribute_key);
// Turns the numbered value into a text value
// $numArray = explode(" ", $sub);
// var_dump($numArray);
$value = print_r($sub, true);
// $value = array_search("att:Subtitle:",$product_tabs);
// $value = array_search("att:Subtitle:", $tabs); // Warning: array_search() expects parameter 2 to be array, null given
// $result = $product_tags['$value']; // my attempt to return the text
// Remove att:Subtittle: in front of the subtitle value to output the clean final value
$subtitle = ltrim($value, 'att:Subtitle:');
}
So far it comes out as a number value where I'm displaying $subtitle... but I can't figure out how to display the custom text value instead.
Any ideas?
Thanks
EDIT: I am working with products that have multiple tags and I do not control these. Out of the tags I'm trying to find the one that starts with att:Subtitle: but only show the custom value after that marker.
When I echo $tags, the ist comes out something like this:
att:Benefit:balance, att:Perfect:Combination Skin, att:Size: 1.8 oz, att:Subtitle: Multi-Tasking Product, Key Ingredient 1, Key Ingredient 2, Essentials, meta-related-product-xyz, meta-related-product-brandname
They will all have a different list of tags
Of course it comes out as a number. You're getting a number from the strpos() and ultimate trying to run ltrim() on it.
If you're expecting the desired text to be in $tags immediately following 'att:Subtitle:' and have nothing else in that string, $subtitle = substr($tags, strpos('att:Subtitle:') + strlen('att:Subtitle:')); should give it to you. If you're expecting it to possibly be an element in the $product_tags array, need to loop (I'm assuming it shows up once, at most):
foreach ($product_tags as $product_tag) {
if (strpos($product_tag, 'att:Subtitle:') !== false) {
$subtitle = substr($product_tag, strpos($product_tag, 'att:Subtitle:') + strlen('att:Subtitle:'));
break;
}
}
So for what I understand you're trying to get rid of 'att:Subtitle:' from the tags on your products descriptions? maybe you should try replacing that value on your tags array
// Using tags to output custom data from products
$tags = $current_product['tags'];
// $tags is a string, this turns the values into an array
$product_tags = explode(',', $tags);
// Get rid of attribute on product tag
for($i = 0; $i < count($product_tags); $i++){
$subtitle = str_replace(':att:Subtitle','',$product_tags[i]);
}

PHP/MySQL - How to adjust query based on the length (characters) within database

I've had excellent support here, so I figured I'd try again, as I have no clue where to even begin looking for this answer.
I have a simple MySQL database, named "testimonials", which contains 3 tables, "id", "name", "content"
What I want to do, is display testimonials within a fixed size block. Just simply displaying the content is no problem at all, however where I'm stuck is the (somewhat) unique way I'm trying to make it work. I would like to display a random item on each page load, and then to check the character length of the "content" within the testimonial, and if it's equal to or greater than XX length, then just display the one testimonial, otherwise if it's less than XX in length to display a second testimonial (assuming it combined with the first doesn't break the container box).
The box in question is 362px in width and 353px in height using 14px font with Verdana. An example of how the testimonial will appear on the page is like this:
"This is the testimonial content, some nice message from a client."
-- Billy Bob, Owner, Crazy Joe's Tavern
The "name" table in the database holds everything in bold (minus the -- of course), in case someone felt the need to ask.
As I typed that, I felt as if I was asking for a miracle, however I'll still post the question, hoping someone might just know the answer. As always, thanks for any help I may get, if this is just simply asking too much, I'm not totally against the idea of only displaying one testimonial at a time making a ground rule saying they have to contain a minimum of XX characters.
Thanks!
Quick Update: I didn't expect to get answers so quickly, I'm not at my desk at the moment, so as soon as I sit back down I'll go through and see which answer fits best. However, do you guys get together and try to make your answer more complex than the previous answer? lol, thanks though, for anyone who's offering help, you guys rock!
Final edit: I decided against this whole idea, as it just way over complicated everything. For the time being, I'm just going to display all testimonials, and make them scroll, while I work on a jQuery snippet to make it prettier. Thanks everyone for your help though! Should I decide again to do this, I'll be trying my chosen answer.
You just need a loop. Pseudo-code:
$length = 0;
$target = 200; // or whatever
while( $length < $target ) {
$comment = getOneComment();
displayComment($comment);
$length += strlen( $comment['content'] ); // assuming getOneComment() returns an associative array
}
To make it pretty, if the display box is going to a be a fixed height, you could use some jQuery to toggle whether to show the second comment on not.
Assuming you have testimonials in an array:
$testimonials = array(
't1' => array(
'content' => 'testimonials 1 content..',
'author' => 'the author'
),
't2' => array(
'content' => 'testimonials 2 content..',
'author' => 'the author 2'
),
);
You could have an maxLengthTestimonialsContent and maxLenthAllTestimonnials variable :
$maxLengthTestimonialsContent = 120;
$maxLenthAllTestimonnials = 240;
And now with a simple loop you build the array testimonials that you will use to show:
$testimonialsToShow = array();
$i = 1; $totalLength = 0
foreach($testimonials as $t) {
if( $i > 1 && strlen( $t['content']) < $maxLengthTestimonialsContent
&& $totalLength < $maxLenthAllTestimonnials )
break; // basically here you test that testimonials less first
// and with less length than maxLengthTestimonial, and also
// total length less than maxLengthAll to be stored
//in $testimonialsToShow
else {
$testimonialsToShow[] = $t;
$totalLength = $t['content'];
}
}
Something like this is what you would need.
<?php
$str = $res["testimonial"];
if (strlen($str) > 50) {
// Logic to retrieve and display second testimonial
}
?>
Obviously there's some more processing you'll have to come up with to determine if the second testimonial is short enough to fit or not. But that should get you started.
EDIT:
For the randomization, I use this on my own site:
$referrals = mysql_query("SELECT id FROM ts_testimonials");
$referralView = array();
$i = 0;
while ($newReferral = mysql_fetch_array($referrals)) {
$referralView[$i] = $newReferral['id'];
$i++;
}
if (sizeof($referralView) >= 1){
$referralTop = rand(0,sizeof($referralView)-1);
$newReferralTop = mysql_fetch_array(mysql_query("SELECT * FROM ts_testimonials WHERE id = '".$referralView[$referralTop]."'"));
if (sizeof($referralView) >=2){
$referralBottom = rand(0,sizeof($referralView)-1);
while ($referralBottom == $referralTop) {
$referralBottom = rand(0,sizeof($referralView)-1);
}
$newReferralBottom = mysql_fetch_array(mysql_query("SELECT * FROM ts_testimonials WHERE id = '".$referralView[$referralBottom]."'"));
}
}

php - build array out of computations from multidimensional array

This is driving me nuts.
I'm attempting to reada CSV file (done) and then work through the permutations of each row.
Each row contains several bits of data (name, price etc.).
Some of them contain slash separated lists (a/b/c/c3/c65).
What I need to do is generate all the possible variations of each row.
Example:
Row 12 =
Name = name,
Price = price,
Models = x12/x14/x56,
Codes = LP1/LP12/LP899/XP90/XP92,
From that I should be able to generate 15 variations, each with the same Name and Price, but with different Codes and varied Models;
Name Price X12 LP1
Name Price X12 LP12
Name Price X12 LP899
~
Name Price X56 XP90
Name Price X56 XP92
Yet I'm either overwriting pre-existing versions, or generating individual versions, but only getting 1 set of values changing (so I may get the 15 versions, but only Model changes, everything else stays the same).
Any help/thoughts or pointers would be appreciated!
So you have one row containing that much items,
say
$row = array('Name'=>'name', 'price'=>'price','models'=>'x12/x14/x56','codes'=>'LP1/LP12/LP899/XP90/XP92')
and you want to split models and codes with "/" then have each item as a new row in the array with all the columns those having the same value for price and name field, here is how you can do this,
$line = 0;
$result_array = array();
$result_array[$line]['name'] = $row['name'];
$result_array[$line]['price'] = $row['price'];
//split the models using explode
$tmpModels = explode("/",$row['models']);
foreach($tmpModels as $mod){
if($line > 0){
$result_array[$line]['name'] = $row['name'];
$result_array[$line]['price'] = $row['price'];
}
$result_array[$line]['model'] = $mod;
$line++;
}
$line = 0;
//now split the codes using explode
$tmpCodes = explode("/",$row['models']);
foreach($tmpCodes as $cod){
$result_array[$line]['code'] = $cod;
$line++;
}
if(count($tmpCodes) > count($tmpModels)){ // then few more rows should be added to include all from codes
foreach($tmpCodes as $cod){
$result_array[$line]['name'] = $row['name'];
$result_array[$line]['price'] = $row['price]'
$result_array[$line]['model'] = '';
$result_array[$line]['code'] = $cod;
$line++;
}
}
$result_array will have what you want.
This code is not tested, so there can be some errors, btw i hope this will surely give you an idea on how to achieve that.
Let's say you have array that looks like this:
$variant=Array();
$list[0]=array('Name'=>'Item name', 'Price'=>'$400','Models'=>'x12/x14/x56','Codes'=>'LP1/LP12/LP899/XP90/XP92');
$list[1]=array('Name'=>'Item name', 'Price'=>'$400','Models'=>'x12/x14/x56','Codes'=>'LP1/LP12/LP899/XP90/XP92'); // and more array.......
for($i=0;$i<count($list);$i++){
$Names=$list[$i]["Name"];
$Prices=$list[$i]["Price"];
$Models=explode("/",$list[$i]["Models"]);
$Codes=explode("/",$list[$i]["Codes"]);
for($i2=0;$i2<count($Codes);$i2++){
$variant[]=Array("name"=>$Names,"price"=>$Prices,"model"=>$Models[0],"code"=>$Codes[$i2]);
$variant[]=Array("name"=>$Names,"price"=>$Prices,"model"=>$Models[1],"code"=>$Codes[$i2]);
$variant[]=Array("name"=>$Names,"price"=>$Prices,"model"=>$Models[2],"code"=>$Codes[$i2]);
// You can add more models by copy paste it and change $Models[2] with next available $Models array index
}
}
var_dump($variant);
?>
The results will produce 30 array, because we have 2 rows, so that's not wrong ... okay
Reason for looping the codes
Because codes is more greater than models. So, we can catch all values.
Good luck, btw i have test it and that's worked

Logic Issue - how many / which small boxes in a big box - PHP/MySQL

I've got a problem, and I'll try and describe it in as simplest terms as possible.
Using a combination of PHP and MySQL I need to fulfil the following logic problem, this is a simplified version of what is required, but in a nutshell, the logic is the same.
Think boxes. I have lots of small boxes, and one big box. I need to be able to fill the large box using lots of little boxes.
So lets break this down.
I have a table in MySQL which has the following rows
Table: small_boxes
id | box_size
=============
1 | 100
2 | 150
3 | 200
4 | 1000
5 | 75
..etc
This table can run up to the hundreds, with some boxes being the same size
I now have a requirement to fill one big box, as an example, of size 800, with all the combinations of small_boxes as I find in the table. The big box can be any size that the user wishes to fill.
The goal here is not efficiency, for example, I don't really care about going slightly under, or slightly over, just showing the different variations of boxes that can possibly fit, within a tolerance figure.
So if possible, I'd like to understand how to tackle this problem in PHP/MySQL. I'm quite competent at both, but the problem lies in how I approach this.
Examples would be fantastic, but I'd happily settle for a little info to get me started.
You should probably look into the glorious Knapsack problem
https://codegolf.stackexchange.com/questions/3731/solve-the-knapsack-problem
Read up on this.
Hopefully you've taking algebra 2..
Here is some PHP code that might help you out:
http://rosettacode.org/wiki/Knapsack_problem/0-1#PHP
Thanks to maxhd and Ugo Meda for pointing me in the right direction!
As a result I've come to something very close to what I need. I'm not sure if this even falls into the "Knapsack problem", or whichever variation thereof, but here's the code I've come up with. Feel free to throw me any constructive criticism!
In order to try and get some different variants of boxes inside the knapsack, I've removed the largest item on each main loop iteration, again, if there's a better way, let me know :)
Thanks!
class knapsack {
private $items;
private $knapsack_size;
private $tolerance = 15; //Todo : Need to make this better, perhaps a percentage of knapsack
private $debug = 1;
public function set_knapsack_size($size){
$this->knapsack_size = $size;
}
public function set_items($items){
if(!is_array($items)){
return false;
}
//Array in the format of id=>size, ordered by largest first
$this->items = $items;
}
public function set_tolerance($tolerance){
$this->tolerance = $tolerance;
}
private function remove_large_items(){
//Loop through each of the items making sure we can use this sized item in the knapsack
foreach($this->items as $list_id=>$list){
//Lets look ahead one, and make sure it isn't the last largest item, we will keep largest for oversize.
if($list["size"] > $this->knapsack_size && (isset($this->items[$list_id+1]) && $this->items[$list_id+1]["size"] > $this->knapsack_size)){
unset($this->items[$list_id]);
}else{
//If we ever get here, simply return true as we can start to move on
return true;
}
}
return true;
}
private function append_array($new_data,$array){
if(isset($array[$new_data["id"]])){
$array[$new_data["id"]]["qty"]++;
}else{
$array[$new_data["id"]]["qty"] = 1;
}
return $array;
}
private function process_items(&$selected_items,$knapsack_current_size){
//Loop the list of items to see if we can fit it in the knapsack
foreach($this->items as $list){
//If we can fit the item into the knapsack, lets add it to our selected_items, and move onto the next item
if($list["size"] <= $knapsack_current_size){
$this->debug("Knapsack size is : ".$knapsack_current_size." - We will now take ".$list["size"]." from it");
$selected_items = $this->append_array($list,$selected_items);
$knapsack_current_size -= $list["size"];
//Lets run this method again, start recursion
$knapsack_current_size = $this->process_items($selected_items,$knapsack_current_size);
}else{
//Lets check if we can fit a slightly bigger item into the knapsack, so we can eliminate really small items, within tolerance
if(($list["size"] <= $knapsack_current_size + $this->tolerance) && $knapsack_current_size > 0){
$this->debug("TOLERANCE HIT : Knapsack size is : ".$knapsack_current_size." - We will now take ".$list["size"]." from it");
$selected_items = $this->append_array($list,$selected_items);
$knapsack_current_size -= $list["size"];
}
}
//Lets see if we have to stop the recursion
if($knapsack_current_size < 0){
return $knapsack_current_size;
}
}
}
private function debug($message=""){
if(!$this->debug){
return false;
}
echo $message."\n";
}
public function run(){
//If any of the variables have not been set, return false
if(!is_array($this->items) || !$this->knapsack_size){
return false;
}
//Lets first remove any items that may be too big for the knapsack
$this->remove_large_items();
//Lets now check if we still have items in the array, just incase the knapsack is really small
if(count($this->items) == 0){
return false;
}
//Now that we have a good items list, and we have no items larger than the knapsack, lets move on.
$variants = array();
foreach($this->items as $list_id=>$list){
$this->debug();
$this->debug("Finding variants : ");
$selected_items = array();
$this->process_items($selected_items,$this->knapsack_size);
$variants[] = $selected_items;
//Remove the largest variant, so we get a new set of unique results
unset($this->items[$list_id]);
}
return $variants;
}
}
$products = array(
array("id"=>1,"size"=>90),
array("id"=>2,"size"=>80),
array("id"=>3,"size"=>78),
array("id"=>4,"size"=>66),
array("id"=>5,"size"=>50),
array("id"=>6,"size"=>42),
array("id"=>7,"size"=>36),
array("id"=>8,"size"=>21),
array("id"=>9,"size"=>19),
array("id"=>10,"size"=>13),
array("id"=>11,"size"=>7),
array("id"=>12,"size"=>2),
);
$knapsack = new knapsack();
$knapsack->set_items($products);
$knapsack->set_knapsack_size(62);
$result = $knapsack->run();
var_dump($result);

str_replace() function and multiple variables?

This is going to be pretty hard to explain, so I'll try to make it as much of a chronological story as possible and end with the question, so that anyone who needs a relatively in-depth idea of what I'm talking about has one :).
I have a theme template with four text containers named primary_headline, primary_subline, secondary_headline and secondary_subtext. The content for each container comes from echo($container_name).
Each container has it's own variable, $container_name, which posts user created content to from a form, contents which sometimes contains the variables $city_name and $ref_name as raw data (i.e. "Hello, I'm from $city_name"), as $city_name and $ref_name has assigned values, for arguments sake let's just say $city_name= Dallas and $ref_name = Facebook.
Originally, I believed that I only wanted the user to be able to use $city_name and $ref_name within the secondary_subtext container, and I was also going to make the option to use $city_name OR $ref_name the choice of the user in the first place (they'd have to select one, or the other, or none - but couldn't select both.
However, I now want to allow $city_name AND $ref_name across all four container variables ($secondary_subtext for example).
So, my question is, how do I go about doing that in the easiest possible fashion?
Here's my old code for good measure:
if($geo_text == "enable") {
$geo_init = include("inc/geo_text.php");
$secondary_headline = str_replace('$city_name', $city_name, $_POST['secondary_headline']); // $_POST data from user
} else($ref_text == "enable") {
$ref_init = include("inc/ref_text.php");
$secondary_headline = str_replace('$ref_name', $ref_name, $_POST['secondary_headline']); // $_POST data from user
} else { $secondary_headline = $_POST['secondary_headline']; }
Any comments/answers etc will be very greatly appreciated :)!!
$placeholders = array('city_name','ref_name');
$include_mapper('geo_text' => 'inc/geo_text.php','ref_text'=>'inc/ref_text.php');
$containers = array('first_headline','scondary_headline');
$found = 0;
foreach ($include_mapper as $map => $include){
if ($$map == "enable"){
include ($include_mapper[$map]);
foreach ($container as $container){
foreach ($placeholders as $placeholder){
$$container = str_replace('$'.$placeholder, $$placeholder, $_POST[$container];
}
}
$found = 1;
break;
}
}
if (!$found){
foreach ($container as $container){
$$container = $_POST[$container];
}
}

Categories