Save array of images to user in Wordpress? - wordpress

Is it possible to save array of images to the user?
I already created a form and I'm at the saving part.
I already have this code:
update_user_meta($user->ID, 'gallery', $_POST['gallery_images']);
gallery_images contains the array of input images in the form.
And I know this is not working. Is it possible to save an array of images in user? If possible, how?
PS.
I'm using the latest version of wordpress.

(Revised answer)
As pointed in the comment to the other answer, you can use media_handle_upload() to upload the images, but since the function only supports single upload, then for multiple uploads, you can set a temporary $_FILES item like so:
// Load upload-related and other required functions.
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
$post_id = 0; // set to the proper post ID, if attaching to a post
$uploaded = []; // attachment IDs
foreach ( $_FILES['gallery_images']['tmp_name'] as $key => $file ) {
// Set a temporary $_FILES item.
$_FILES['_tmp_gallery_image'] = [
'name' => $_FILES['gallery_images']['name'][ $key ],
'type' => $_FILES['gallery_images']['type'][ $key ],
'size' => $_FILES['gallery_images']['size'][ $key ],
'tmp_name' => $file,
'error' => $_FILES['gallery_images']['error'][ $key ],
];
// Upload the file/image.
$att_id = media_handle_upload( '_tmp_gallery_image', $post_id );
if ( ! is_wp_error( $att_id ) ) {
$uploaded[] = $att_id;
}
}
unset( $_FILES['_tmp_gallery_image'] );
// Save the attachment IDs.
$user = wp_get_current_user();
update_user_meta( $user->ID, 'gallery', $uploaded );
And I'm saving the attachment IDs, but of course, it's up to you if you'd rather save the image URLs, etc.
PS: You can check the original answer here to see how you can also upload the images using media_handle_sideload(). (It works well, but instead of going through a wrapper (function), we should just call media_handle_upload() unless if you're "uploading" external/remote image/file.) Sorry about that answer.. :)

You can serialize the data, and when you need it unserialize it.
update_user_meta($user->ID, 'gallery', serialize($_POST['gallery_images']));
serialize:
https://www.php.net/manual/fr/function.serialize.php

Related

Custom product attributes is blank even though I add it [duplicate]

The products in my clients website require certain attributes which I have added via Products -> Attributes in the Wordpress administration. In this import script I'm coding I need to use the function update_post_meta($post_id, $meta_key, $meta_value) to import the proper attributes and values.
Currently I have the function like so:
update_post_meta( $post_id, '_product_attributes', array());
However I'm not sure how to properly pass along the attributes and their values?
Right so it took me a while to figure it out myself but I finally managed to do this by writing the following function:
// #param int $post_id - The id of the post that you are setting the attributes for
// #param array[] $attributes - This needs to be an array containing ALL your attributes so it can insert them in one go
function wcproduct_set_attributes($post_id, $attributes) {
$i = 0;
// Loop through the attributes array
foreach ($attributes as $name => $value) {
$product_attributes[$i] = array (
'name' => htmlspecialchars( stripslashes( $name ) ), // set attribute name
'value' => $value, // set attribute value
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
// Example on using this function
// The attribute parameter that you pass along must contain all attributes for your product in one go
// so that the wcproduct_set_attributes function can insert them into the correct meta field.
$my_product_attributes = array('hdd_size' => $product->hdd_size, 'ram_size' => $product->ram_size);
// After inserting post
wcproduct_set_attributes($post_id, $my_product_attributes);
// Woohay done!
I hope this function will help other people if they need to import multiple attributes pro-grammatically in WooCommerce!
I tried Daniel's answer, and it didn't work for me. It might be that the Wordpress/Woocommerce code has changed since, or perhaps I didn't quite understand how to do it, but either way that code did nothing for me. After a lot of work using it as a base, however, I came up with this snippet of code and put it on my theme's functions.php:
function wcproduct_set_attributes($id) {
$material = get_the_terms( $id, 'pa_material');
$material = $material[0]->name;
// Now update the post with its new attributes
update_post_meta($id, '_material', $material);
}
// After inserting post
add_action( 'save_post_product', 'wcproduct_set_attributes', 10);
With this, I can take what I set as "material" on my WooCommerce install as a custom attribute and add it to the formal meta as _material. This in turn allows me to use another snippet of code so the WooCommerce search function extends to meta fields, meaning I can search for a material in the WooCommerce search field and have all items with that material appear.
I hope this is useful to somebody.
#Daniels's answer works, won't decide on right or wrong, however if you want to add the values as a taxonomy term under attributes you have to adapt the code as below (set is_taxonomy = 1). Otherwise Woocommerce sees it as custom meta field(?). It still adds the value under attributes. This will only work for strings. For values that are arrays the code has to be adapted.
Additionally it uses the wp_set_object_terms that #Anand suggests as well. I was using that, because all the documentation I could find led to believe that had to be used. However if one only uses the wp_set_object_terms then I couldn't see the attributes in the edit product screen. Using the information from both answers and reading on the subject resulted in the solution.
You will need to tweak the code for things such as product variations.
/*
* Save Woocommerce custom attributes
*/
function save_wc_custom_attributes($post_id, $custom_attributes) {
$i = 0;
// Loop through the attributes array
foreach ($custom_attributes as $name => $value) {
// Relate post to a custom attribute, add term if it does not exist
wp_set_object_terms($post_id, $value, $name, true);
// Create product attributes array
$product_attributes[$i] = array(
'name' => $name, // set attribute name
'value' => $value, // set attribute value
'is_visible' => 1,
'is_variation' => 0,
'is_taxonomy' => 1
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
Then call the function:
$custom_attributes = array('pa_name_1' => $value_1, 'pa_name_2' => $value_2, 'pa_name_3' => $value_3);
save_wc_custom_attributes($post_id, $custom_attributes);
Thank you for posting the code Daniel & Anand. It helped me a great deal.
Don't know if this is the "correct" way to do this... But I needed a function to add ACF repeater fields with a date value as a attribute on post save, so this was the function I came up with:
add_action( 'save_post', 'ed_save_post_function', 10, 3 );
function ed_save_post_function( $post_ID, $post, $update ) {
//print_r($post);
if($post->post_type == 'product')
{
$dates = get_field('course_dates', $post->ID);
//print_r($dates);
if($dates)
{
$date_arr = array();
$val = '';
$i = 0;
foreach($dates as $d)
{
if($i > 0)
{
$val .= ' | '.date('d-m-Y', strtotime($d['date']));
}
else{
$val .= date('d-m-Y', strtotime($d['date']));
}
$i++;
}
$entry = array(
'course-dates' => array(
'name' => 'Course Dates',
'value' => $val,
'position' => '0',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
)
);
update_post_meta($post->ID, '_product_attributes', $entry);
}
}
}
Hope this helps someone.

Get attachment ID by file path in WordPress

I know the path of the file and I like to get the attachment ID.
There's a function wp_get_attachment_url() which requires the ID to get the URL but I need it reverse (with path not URL though)
UPDATE: since wp 4.0.0 there's a new function that could do the job. I didn't tested it yet, but it's this:
https://developer.wordpress.org/reference/functions/attachment_url_to_postid/
OLD ANSWER: so far, the best solution I've found out there, is the following:
https://frankiejarrett.com/2013/05/get-an-attachment-id-by-url-in-wordpress/
I think It's the best for 2 reasons:
It does some integrity checks
[important!] it's domain-agnostic. This makes for safe site moving. To me, this is a key feature.
I used this cool snipped by pippinsplugins.com
Add this function in your functions.php file
// retrieves the attachment ID from the file URL
function pippin_get_image_id($image_url) {
global $wpdb;
$attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url ));
return $attachment[0];
}
Then use this code in your page or template to store / print / use the ID:
// set the image url
$image_url = 'http://yoursite.com/wp-content/uploads/2011/02/14/image_name.jpg';
// store the image ID in a var
$image_id = pippin_get_image_id($image_url);
// print the id
echo $image_id;
Original post here: https://pippinsplugins.com/retrieve-attachment-id-from-image-url/
Hope ti helps ;)
Francesco
Try attachment_url_to_postid function.
$rm_image_id = attachment_url_to_postid( 'http://example.com/wp-content/uploads/2016/05/castle-old.jpg' );
echo $rm_image_id;
More details
None of the other answers here appear to work properly or reliably for a file path. The answer using Pippin's function also is flawed, and doesn't really do things "the WordPress Way".
This function will support either a path OR a url, and relies on the built-in WordPress function attachment_url_to_postid to do the final processing properly:
/**
* Find the post ID for a file PATH or URL
*
* #param string $path
*
* #return int
*/
function find_post_id_from_path( $path ) {
// detect if is a media resize, and strip resize portion of file name
if ( preg_match( '/(-\d{1,4}x\d{1,4})\.(jpg|jpeg|png|gif)$/i', $path, $matches ) ) {
$path = str_ireplace( $matches[1], '', $path );
}
// process and include the year / month folders so WP function below finds properly
if ( preg_match( '/uploads\/(\d{1,4}\/)?(\d{1,2}\/)?(.+)$/i', $path, $matches ) ) {
unset( $matches[0] );
$path = implode( '', $matches );
}
// at this point, $path contains the year/month/file name (without resize info)
// call WP native function to find post ID properly
return attachment_url_to_postid( $path );
}
Cropped URLs
None of the previous answers supported ID lookup on attachment URLs that contain a crop.
e.g: /uploads/2018/02/my-image-300x250.jpg v.s. /uploads/2018/02/my-image.jpg
Solution
Micah at WP Scholar wrote a blog post and uploaded the code to this Gist. It handles both original and cropped URL lookup.
I included the code below as a reference but, if you find useful, I'd encourage you to leave a comment on his post or star the gist.
/**
* Get an attachment ID given a URL.
*
* #param string $url
*
* #return int Attachment ID on success, 0 on failure
*/
function get_attachment_id( $url ) {
$attachment_id = 0;
$dir = wp_upload_dir();
if ( false !== strpos( $url, $dir['baseurl'] . '/' ) ) { // Is URL in uploads directory?
$file = basename( $url );
$query_args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
'key' => '_wp_attachment_metadata',
),
)
);
$query = new WP_Query( $query_args );
if ( $query->have_posts() ) {
foreach ( $query->posts as $post_id ) {
$meta = wp_get_attachment_metadata( $post_id );
$original_file = basename( $meta['file'] );
$cropped_image_files = wp_list_pluck( $meta['sizes'], 'file' );
if ( $original_file === $file || in_array( $file, $cropped_image_files ) ) {
$attachment_id = $post_id;
break;
}
}
}
}
return $attachment_id;
}
Another pro with this solution is that we leverage the WP_Query class instead of making a direct SQL query to DB.
Find IDs for resized images, PDFs and more
Like GFargo pointed out, most of the answers assume the attachment is an image. Also attachment_url_to_postid assumes a url (not a file path).
I believe this better answers the actual question when supplied a file (with path):
function getAttachmentIDFromFile($filepath)
{
$file = basename($filepath);
$query_args = array(
'post_status' => 'any',
'post_type' => 'attachment',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
),
)
);
$query = new WP_Query($query_args);
if ($query->have_posts()) {
return $query->posts[0]; //assume the first is correct; or process further if you need
}
return 0;
}
Based on the answer from #FrancescoCarlucci I could do some improvements.
Sometimes, for example when you edit an image in WordPress, it creates a copy from the original and adds the copys upload path as post meta (key _wp_attached_file) which is not respected by the answer.
Here the refined query that includes these edits:
function jfw_get_image_id($file_url) {
$file_path = ltrim(str_replace(wp_upload_dir()['baseurl'], '', $file_url), '/');
global $wpdb;
$statement = $wpdb->prepare("SELECT `ID` FROM `wp_posts` AS posts JOIN `wp_postmeta` AS meta on meta.`post_id`=posts.`ID` WHERE posts.`guid`='%s' OR (meta.`meta_key`='_wp_attached_file' AND meta.`meta_value` LIKE '%%%s');",
$file_url,
$file_path);
$attachment = $wpdb->get_col($statement);
if (count($attachment) < 1) {
return false;
}
return $attachment[0];
}

Is it possible to update post meta from array in one call?

Code snippet:
$save_dbarray = array(
'email' => 'email#email.se',
'adress' => 'adress'
);
//Save values from created array into db
foreach($save_dbarray as $meta_key=>$meta_value) {
update_post_meta($post_id, $meta_key, $meta_value);
}
Is there any way to optimize above code? In this simple scenario, it wouldn't matter, but If I have a large array then I guess it might be performance issues when updating?
I would like to do something like:
update_post_meta($post_id, $save_dbarray);
Is this possible?
While the other answers are creative solutions to your problem, they don't seem to address the actual issue or answer your question.
The Answer
No. WordPress's update_post_meta only works on one field at a time. Your best bet is to stick with the method you're using above, with the foreach loop. The other answers provide ways of storing that meta in a single field, which is probably fine for some but (as in my case) some need to query against those values, and having a serialized or JSON-encoded array doesn't cut it.
Unfortunately, WP provides no "bulk meta update" method, and if it did, it would likely be a foreach loop. You can always write a function to help make your code cleaner, at least:
<?php
function update_post_meta_array( $post_id, $meta ) {
if ( ! get_post( $post_id ) || ! is_array( $meta ) || empty( $meta ) ) {
return false;
}
foreach ( $meta as $meta_key => $meta_value ) {
update_post_meta( $post_id, $meta_key, $meta_value );
}
return true;
}
phatskat is correct in that there's no built-in way to do this and a foreach loop is required.
This is the most efficient I've found - wrote about it in a blog post as well:
add_action('init', 'bulk_update_post_meta_data');
function bulk_update_post_meta_data() {
$args = array(
'posts_per_page' => -1,
'post_type' => 'POSTTYPEHERE',
'suppress_filters' => true
);
$posts_array = get_posts( $args );
foreach($posts_array as $post_array) {
update_post_meta($post_array->ID, 'POSTMETAKEY', 'NEWVALUE');
}
}
Why not try with serialize() like this:
According to update_post_meta() documentation you can pass the $meta_value as array, that will be serialized into a string.
$save_dbarray = array(
'email' => 'email#email.se',
'adress' => 'adress'
);
update_post_meta($post_id, 'my_custom_fields', $save_dbarray);
Possible multiple value at a time you can your value genearte escaped_json
$escaped_json = '{"key":"value with \\"escaped quotes\\""}';
update_post_meta( $id, 'double_escaped_json', wp_slash($escaped_json) );

Wordpress Profile File / Page

I would like to create a file in the Wordpress theme, where i will add my own code, edit profile, show profile information, and perhaps an ability to insert posts / meta data programmatically.
So it needs to be www.mysite.com/profile.php or www.mysite.com/profile/
I do not want to use Buddy Press or any other plugin.
I know how the template system works, i do not want a page template.
It will probably be a class, later on, i do not want to change .htaccess file, and if i must i would appreciated filter function how to do this from functions.php
Basically just a simple .php file i can link to, located in theme root.
include('../../../wp-load.php');
and write any code i would like to.
Any creative solution that is not too "hacky" would be appreciated.
Spent around 2 days googling bashing my head on this, before i decided to ask question.
Thank you very much.
Ok, I managed to do this, took me 2 days to figure it out. Here is how I managed to do it:
Make a plugin folder.
In that plugin folder make 1x php file. so index.php
Ok so first thing we need to register plugin I did it like this, in your index.php paste
this code.
function activate_profile_plugin() {
add_option( 'Activated_Plugin', 'Plugin-Slug' );
/* activation code here */
}
register_activation_hook( __FILE__, 'activate_profile_plugin' );
Then we need a function when you register a plugin only once register profile pages.
function create_profile_page( $title, $slug, $post_type, $shortcode, $template = null ) {
//Check if the page with this name exists.
if(!get_page_by_title($title)) {
// if not :
$page_id = -1;
$page_id = wp_insert_post(
array(
'comment_status' => 'open',
'ping_status' => 'open',
'post_content' => $shortcode,
'post_author' => 1, // Administrator is creating the page
'post_title' => $title,
'post_name' => strtolower( $slug ),
'post_status' => 'publish',
'post_type' => strtolower( $post_type )
)
);
// If a template is specified in the function arguments, let's apply it
if( null != $template ) {
update_post_meta( get_the_ID(), '_wp_page_template', $template );
} // end if
return $page_id;
}
}
Ok so we created function which programatically register pages. It has 5 paramethers.
is Title
Slug
Post type
Shortcode.
Template
For the shortcode template you need to make a shortcode with the complete page output
and add it as a parameter to this function, so for registration page it will be a shortcode with the registration forms etc.
For example :
function registration_shortcode(){
echo 'Wellcome to Registration page';
}
add_shortcode('registration_output', 'registration_shortcode');
Next thing we need to call it once only when plugin loads.
so we do this :
function load_plugin() {
if ( is_admin() && get_option( 'Activated_Plugin' ) == 'Plugin-Slug' ) {
delete_option( 'Activated_Plugin' );
/* do stuff once right after activation */
// example: add_action( 'init', 'my_init_function' );
create_profile_page('Registration', 'registration', 'page', '[registration_output]');
create_profile_page('Profile', 'profile', 'page', '[profile_shortcode]');
create_profile_page('Profil Edit', 'profile-edit', 'page', '[edit_shortcode]');
}
}
add_action( 'admin_init', 'load_plugin' );
Ok so this will execute only once when plugin loads and it will create 3 Pages, which are Profile, Registration and Profile Edit.
And that's it, you have your front-end user profile blank pages, and you can write page output in shortcodes ,create more pages, put any forms or elements you like and create decent profile (which doesn't have any stuff you don't need in it like plugins. )
Hope this helps, it was painful for me to figure this out. Cheers!

Buddypress bp_activity_add(activity_action) hides the link "target"

I'm developing a social network with Buddypress, I created a RSS plugin to pull the RSS feed from the specified websites.
Everything is working, except when the RSS is posted to the activity stream. When I create the activity content to print a link, I set the link target to "_new" to open it in a new page.
Here's the code:
function wprss_add_to_activity_feed($item, $inserted_ID) {
$permalink = $item->get_permalink();
$title = $item->get_title();
$admin = get_user_by('login', 'admin');
# Generates the link
$activity_action = sprintf( __( '%s published a new RSS link: %s - ', 'buddypress'), bp_core_get_userlink( $admin->ID ), '' . attribute_escape( wprss_limit_rss_title_chars($title) ) . '');
/* Record this in activity streams */
bp_activity_add( array(
'user_id' => $admin->ID,
'item_id' => $inserted_ID,
'action' => $activity_action,
'component' => 'rss',
'primary_link' => $permalink,
'type' => 'activity_update',
'hide_sitewide' => false
));
}
It should come up with something like that:
Test
But it prints like that:
Test
Why is this happening?
The 'target' attribute is probably getting stripped by BuddyPress's implementation of the kses filters. You can whitelist the attribute as follows:
function se16329156_whitelist_target_in_activity_action( $allowedtags ) {
$allowedtags['a']['target'] = array();
return $allowedtags;
}
add_filter( 'bp_activity_allowed_tags', 'se16329156_whitelist_target_in_activity_action' );
This probably won't retroactively fix the issue for existing activity items - it's likely that they had the offending attribute stripped before being stored in the database. But it should help for future items.

Resources