complicated meta_values
-
I have a metabox that creates a non-scalar array of data, which is serialized by default by WP.
Remember that the array is multidimensional, with two levels.
On the front end, I retrieve the data (array values) with get_post_meta( $ARRAYNAME ), which automatically unserializes the array.$test = get_post_meta( $post->ID, 'productdata_group', true );Then I extract the values of the specific keys, for example manually:
$subtest = $test[1]['article'];etceteraWhile in functions.php, in the structure function referring to add_meta_box() that creates the metabox for the admin page, the method is:
if ( $array ) : foreach ( $products_array as $field )etcetera, then, by calling, for example,$field['article'];I get the list of values for the ‘article’ key.The metabox is a table where each row is an input, so I call, for example:
<input name="article[]" value="<?php if ( $field['article'] != '' ) echo esc_attr( $field['article'] );?>"etcetera.When I call the data individually (outside the table), for example with:
$test = esc_attr( $field['article'] );
I only get a sequential list of all the values referenced by that key, but I’d like to call them specifically on a case-by-case basis:
It’s an echo to write a couple of CSS lines to be put as content :after, calling the variable for each value. In this CSS echoed $test should call all the values in the various rows, but instead it only gives me the value of the last row.I already used with success this method (the inline css for single meta_data, just calling them with get_meta_box() ) but in this case it’s more complicated.
I hope I explained myself clearly.
I tried foreach loop, for loop, array_column, get_metadata(), wp_get_attachment(), … nothing.Any suggestion? Thanks in advance.
-
What does the code for the output in the meta box look like? I suspect a typo in the loop that displays the fields is the cause. Take a closer look at that.
thank you very much for your reply, later I will post the code, from warning messages there is an error in loop (array to string, no array, etc), and when I call $field[‘image’] (where image is the sub array key) it gives me only last one of the list. I’m checking for any typo error
my doubt is that it could be related to the particular call: a css where I want to call the variable as :after content .. strange because I invented this method and works fine for any normal meta_value (for normal I mean non-scalar arrays)
and in fact it works also in this case, but gives me only last value of $field[‘image’], so I try to add a loop “foreach $array as $key => $value” but no good result
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
In the
$callbackfunction ofadd_meta_box()I have a table with number of rows incremented by “add/remove” buttons
(repeatable, for wich I use some jQuery script), and each row contains 4 inputs as “sub meta_keys” where per each one are added the “sub post_meta values“.
The whole array structure is called ‘productdata_group’ and the general function “get_post_meta()” is called with the var$products_array.
After thorough tests it works perfectly.The result is a multilevel array, where in the 2nd levels there are the 4 keys and the 4 values (corresponding to one row of the table), then the number of rows is increased by the operator based on the quantity of items to be presented.
Here is the print_r() of a test.Array
(
[0] => Array
(
[article] => crema solare
[image] => BeeHoney.webp
[description] => da spalmare
[price] => 1000
)
[1] => Array
(
[article] => lipstick
[image] => BeePropolis.webp
[description] => da mettere sulle labbra
[price] => 500
)
)Of the 4 keys, 3 are just input type=”text” (very simple), while the 4th (the 2nd in order) is an image of the article, picked with input type=”file”, which I tweak (customize) with a method that I already applied dozen of times with succes: f.e. in the text line in front-end I hide the input-file standard wording and add a text css
:aftercontaining only the name of the selected file (which remains once updated the metabox).An example of row / at the piece of input type=”file” is:
<td><input type="file" id="artimg" class="widefat" name="image[]" value="<?php if ( $field['image'] != '' ) echo esc_attr( $field['image'] ); ?>" accept="image/*" required /></td>Normally (with standard single metaboxes) my method to tweak the input file is:
in external “admin” css:input[type="file"]:after {visibility: visible; … etcetera}
in internal css echoed in functions.php:echo ' … ' if ( ! empty( $anyvariable ) ) : echo ' … 'ROOT: ../path/..: ' . $anyvariable . '"; … etcetera (where $anyvariable is the var calling that specific filename)
and$anyvariableis before identified with:$anyvariable = get_post_meta( $post->ID, 'post_type name', true );
it works well.
(sometimes in javascript I also replace the fake path, using<img src="../../wp-content/uploads/specificfolder/' + x.replace("C:\fakepath\", "") + … etcetera).But in this case of course I cannot use this method, because the meta_values are many, in a complex array.
…
being at the beginning of the function: “if ( $products_array ) : foreach ( $products_array as $field ) { …“
and in each “value=”$field['image']“
I initially started to use:$img = echo esc_attr( $field['image'] );… but with this method it calls the last one meta_value per each row, missing the specific one
(for example if the displayed articles are: Honey.webp, Apple.wepb, Pear.webp (just examples), it gives me “Pear.webp” per each line).
While if I echo them for testing,echo $img . '<br />';it correctly displays all values (image files) present in the table (but only with echo, while calling the variable it becomes always the same, last one).
This because I need to start with a loop such as foreach() or for loop for ($n = 0, $n < count (after defined what to count), $n++). I also tried the foreach ($array as $key => $value), or to retrieve the values with array_column() but for the moment no success.
Really crazy: I obtain the echo of full values, but applying same variable no.
I have done dozens of trials.
For explample I tried:foreach ($products_array as $key => $value) {
$cnt1 = count( $products_array[$key] );
echo $cnt1 . '<br />';
}it gives me the ordered list of keys
—
foreach ($products_array as $key) {
$cnt = count( $products_array );
}
for ( $n = 0; $n < $cnt; $n++ ) {
$img = $products_array[$n]['image'];
echo '<style>
#productlistbox #artimg:after {
content: "';
if ( ! empty( $img ) ) :
echo 'ROOT: ../forever/..: ' . $img . '";
color: #f00;';
else :
echo '\00A0 - - -";';
endif;
echo '
}
</style>
';
}But again gives only the latest value in each row.
Probably I have spent too many hours and now I have a mess of trials. Happens. Surely a typo error somewhere.Thanks for your help.
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
I want to be able to call the value of $field[‘image’] specific to that row, row by row
This at the beginning of your code is unnecessary:
foreach ($products_array as $key) {
$cnt = count( $products_array );
}If you are concerned with the number of entries in $products_array, the following is sufficient:
$cnt = count( $products_array );If it is still not correct, I would recommend the following:
- Use var_dump() to see which value each variable has at which point. This will help you find out where you may have gone wrong.
- Check any entries in error.log in this regard and adjust your code accordingly.
Unfortunately, since I still don’t see an example of how your
$products_arrayis structured, I can’t give you any more specific tips because I can’t reproduce it on my end.Threadi, I didn’ post the whole code because wp cuts some areas, and it is long. So I tried to explain in words. I can send you in some other way. Anyhow I will check in error.log, I used only main alerts of DevTools to check.
Anyhow I used print_r() instead, and I repeat you that most of several trials work fine, properly giving all the values I extracetd, but then, when I apply the code to have the values line by line it doesn’t work. I guess that the reason is the following: the array keys are unique, so when I call all keys “image”, the last one overwrites all previous ones .. and as a consequence also values are replaced with last one.
For example in test I have three values in sequence for ‘image’ key:
- RoyalJelly.webp
- BeeHoney.webp
- BeePropolis.webp
but when I echo them per each row with the var $img, it writes:
- BeePropolis.webp
- BeePropolis.webp
- BeePropolis.webp (i.e. it repeats only the last one per each row)
I’ve figured it out (!), but I fear the solution will be difficult or even impossible:
The problem doesn’t stem from errors in the PHP code, but from my CSS method:
In fact, to replace the native text of the input type file, with the name of the selected file, I use a CSS style in which the “no file chosen” text (etc.) is invisible, and I put the name of the selected file (in this case, php echo $field[‘image’];) as ::after.
In fact, the simple PHP code put as value=”…” would work perfectly, but (obviously) I can’t inline the ::after pseudo-element in the echo, so I’m forced to add a separate piece of echoed CSS ().
This method works when dealing with a simple metabox with a value, but it doesn’t work when dealing with a complex array.
Because in that case (in the echoed CSS), any loop is useless: it will always return the last value called for all rows.
I’m trying to find a way to replace the classic... value="<?php echo "meta_value"; ?>" ...by displaying it with a ::after.
I’m trying to place the CSS before instead of after the input.-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
So:
- in css input[type=”file”] value hidden by font-size:0, and replaced with :after at font-size:1em
- :after should therefore be my php echo in the file input value
- if I have a metabox with a single or multiple meta_values, but a string, obviously each is applied one by one to its specific input
- if instead I have an array, it takes only the last meta_value of a meta_key (because the meta_key has a unique id and therefore the last, or the first depending on how the code is written, overwrites all the others)
- (infact $img = $products_array[$n][‘image’]; $img is an array and when I try to apply it with foreach loop warning says “array to string conversion”)
- so in the case of an array, I should be able to write the contents of :after inline, but this obviously isn’t possible because the pseudo-element isn’t part of the DOM
- and it’s not even possible to do it through a css with a logical condition in php (if css string, else css string) as for the simple meta_value
- so apparently there’s no way to apply my tweak to the default wording of the file input in the case of arrays
- I therefore need to find an alternative solution, which could be in js, or I’ve seen on the web that some people use the label to replace the native text of the input type file.
(sorry for the multiple edits of what I text, but the matter is so complicated that I adjust the text trying to be as clear as possible)
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
update: I solved simply removing the :after pseudio-element and called the name of selected file with a label … yes, php was working fine all along, the problem was calling the metadata of an array through a css :after
<td><label id="imglbl">
<input type="file" id="artimg" name="image[]" value="" accept="image/*" />
<?php $img = esc_attr( $field['image'] );
if ( $img != '' ) : echo 'Immagine : ' . $img; else : echo '- - -'; endif ?>
</label></td>No need further js
@threadi, now I have another problem: sigh .. one of my repeatable inputs is a filepicker (input type file with some tweak) … when I use such file picking method with standard (single) metabox it’s easy, update_post_meta() keeps the selected file at every update, because the value is targeted only to that .. but with an array of metavalues my update_post_meta must be targeted to the whole array:
so when I update, all the input type text keep the value (obviously) but the input type file loes all the previous values (selected filenames), because that input is readonly.
I need to store the value in a hidden input and replace at every metabox update, or find a solution to keep safe the files previously selected and saved as meta_values.
this is an example only of a metabox with input type file, where I can update the page 1000 times but it does not lose the previously chosen videoclip. In fact I added a checkbox to check for eventual need of deletion: the videoclip metavalue is deleted only if I check “delete”:
function avweb_videoclip_metadata_save( $post_id ) {
if ( ! isset( $_POST['avweb_videoclipbg_nonce'] ) || ! wp_verify_nonce( $_POST['avweb_videoclipbg_nonce'], basename( __FILE__ ) ) ) {
return;
}
else if ( ! isset( $_POST['avweb_videoclip_nonce'] ) || ! wp_verify_nonce( $_POST['avweb_videoclip_nonce'], basename( __FILE__ ) ) ) {
return;
}
global $post;
$post_type = get_post_type_object( $post->post_type );
if ( ! current_user_can( 'edit_pages' ) || ! current_user_can( 'edit_posts', $post_id ) ) {
// alert formatted with Georgia font-family
echo '<script>alert( "𝑨𝑻𝑻𝑬𝑵𝒁𝑰𝑶𝑵𝑬(!):<br/><br/>𝑛𝑜𝑛 ℎ𝑎𝑖 𝑖 𝑝𝑒𝑟𝑚𝑒𝑠𝑠𝑖 𝑝𝑒𝑟 𝑝𝑢𝑏𝑏𝑙𝑖𝑐𝑎𝑟𝑒 𝑚𝑜𝑑𝑖𝑓𝑖𝑐ℎ𝑒" )</script>';
return;
}
// save metadata
if ( 'videoclips' === get_current_screen()->id ) {
// background-image
if ( isset( $_POST['videoclipbg'] ) && ! empty( $_POST['videoclipbg'] ) ) {
update_post_meta( $post_id, 'videoclipbg', strip_tags( $_POST['videoclipbg'] ) );
}
// videoclip
// video deletion (saved conditionally)
if ( isset( $_POST['delvideo'] ) ) {
update_post_meta( $post_id, 'delvideo', 1 );
} else {
delete_post_meta( $post_id, 'delvideo' );
}
// save video (if not checked deletion checkbox)
if ( isset( $_POST['videoclip'] ) && ! empty( $_POST['videoclip'] ) && ! isset( $_POST['delvideo'] ) ) {
update_post_meta( $post_id, 'videoclip', $_POST['videoclip'] );
}
else if ( isset( $_POST['delvideo'] ) ) {
delete_post_meta( $post_id, 'videoclip', $_POST['videoclip'] );
}
}
}
add_action( 'save_post', 'avweb_videoclip_metadata_save' );there are other pieces but don’t care to those ones (background, etc.)
But with an array metabox:
if ( ! empty( $last ) && $new != $previous ) {
update_post_meta( $post_id, 'productdata_group', $last );In this way the input with selected image file is lost after refresh.
-
This reply was modified 2 months, 1 week ago by
Mauro Vicariotto.
amend the above code (typo error):
if ( ! empty( $last ) && $last != $previous ) {
update_post_meta( $post_id, 'productdata_group', $last );where: $last is the array of the several inputs (text and file) and $previous is get_post_meta() of the previous situation: in this way update the metavalues, it keeps all but loses the selected file
Just for info: completed the incremental metabox which stores a serialized array metakey including a file picker. The function for the data table contains jQuery to manage add/remove row buttons (each line) and to keep the metavalue of choosen image where a file-input passes the value to an hidden input, and the hidden is the one that sends the metavalue on update:
jQuery
// input-file value to input-hidden to preserve it on update
$( '.file-pick' ).on( 'change', function() {
// input-file value (delete fakepath)
var filename = $( this ).val().replace( /C:\\fakepath\\/i, '' );
// copy it only if not empty
if ( filename != null ) {
$( this ).closest('tr').find( '.file-store' ).val( filename );
}
});Thanks for your initial feedback (even if then disappeared). Now I close the topic which I resolved.
-
This reply was modified 2 months, 1 week ago by
You must be logged in to reply to this topic.