I'm using ACF with WordPress and I have a form that I am trying to add a validation error to, but it doesn't appear to be working (I think I know why)...
My code:
function my_acf_update_value( $value, $post_id, $field ) {
// Get the users numerical user id
$user_id = str_replace('user_', '', $post_id);
$value = sanitize_text_field($value);
/** #noinspection PhpParamsInspection */
$user_data = wp_update_user(array('ID' => $user_id, 'user_email' => $value ) );
if ( is_wp_error( $user_data ) ) {
$wp_error = $user_data->get_error_message();
$input = $field['prefix'] . '[' . $field['key'] . ']';
acf_add_validation_error($input, $wp_error);
}
return $value;
}
add_filter('acf/update_value/key=field_5c121023e119f', 'my_acf_update_value', 10, 3);
As you may be able to tell I am attempting to update the users email address field (default WP one) based off the email provided by a user in an email field on a frontend ACF Form.
I then check to see if the update caused any errors and obviously if it did I want to add to the ACF validation errors, but it passers through successfully.
I assume this is because the update function runs AFTER the validation and this is why it isn't working?
Because of this I thought about doing the update in the validation function such as:
function my_acf_validate_value( $valid, $value, $field, $input ){
// bail early if value is already invalid
if( !$valid ) {
return $valid;
}
// Some code...
// Return error here?
return $valid;
}
add_filter('acf/validate_value/key=field_5c121023e119f', 'my_acf_validate_value', 10, 4);
...but I don't seem to have access to the $post_id here, nor does this seem like the best way to handle it?
Is there a way to handle this better?
You can use var_dump to see what data you have within the function - either in one of the existing function attributes, or by using get_the_ID() or global $post; to access the current Post object. Beware when trying to manipulate the Post object here, though.
Related
I am trying to send post data to third-party services when the post is saved via API. I am using hook add_action( 'save_post', [$this, 'save_post_callback'], 100, 3); but this hook seems to be called in update post as well as post-new.php in admin panel. So to get rid of running this hook in post-new.php, I have checked the $_POST request but I am not able to filter the update post since I want to call API only in save the post, not in an update.
There seems to be the third parameter in callback function $update but it's not working either. Below is my code that needs to be called only in save a post but it's not working. Any help would be greatly appreciated.
function save_post_callback( $post_id, $post, $update ) {
// (!$update) => this doesnot seems to work
if(!empty($_POST) && $post->post_type == "post"){
//run only when save post
}
}
simple way is to check if _wp_http_referer last part is post-new.php or not.
here is a simple code
function save_post_callback($post_id, $post, $update)
{
// (!$update) => this doesnot seems to work
if ( ! empty($_POST) && $post->post_type == "post" ){
$end = explode('/', $_POST[ '_wp_http_referer' ]);
$end = end($end);
if($end == 'post-new.php'){
//echo 'it is new post';exit();
//do what you want here.
}
}
}
From StackExchange here. It looks like a clever way is to compare the post_date & post_modified to determine it is a new post.
$is_new = $post->post_date === $post->post_modified;
if ( $is_new ) {
// first publish
}
I'm trying to write a function where logged in users can add favorite properties and store it as an array in user meta table, but instead of adding multiple values it just stores one value and keeps on replacing it. What am I doing wrong here? I was also unsuccessful to add it manually in the database, how to read the structure?
This is for WordPress
function wms_add_to_usermeta( $post_id )
{
$favorites = $this->wms_get_user_meta();
$favorites[] = $post_id;
$this->wms_update_user_meta( $favorites );
return true;
}
WMS GET USER META Function
function wms_get_user_meta( $user = "" )
{
if( ! empty( $user ) ) {
$userdata = $this->get_user_by( 'login', $user );
$user_id = $userdata->ID;
return get_user_meta( $user_id, $this->favorites_meta_key, true );
}
else {
return get_user_meta( $this->wms_get_user_id(), $this>favorites_meta_key, true );
}
}
Update User Meta
function wms_update_user_meta( $arr )
{
return update_user_meta( $this->wms_get_user_id(), $this->favorites_meta_key, $arr );
}
table data structure a:1:{i:0;i:7;} it keeps on replacing i:7; with 7 being the $post_id
You define $favorites when you call mws_get_user_meta in your class. Then you re-declare $favorites as an array when you add the brackets after it, but that is ignored because it is already an array, or as Alex suggests your array might lose it's format when you do that. Then with the = you push the post_id so it ends up at the end of the array.
So you end up with:
$this->wms_update_user_meta( array('stuff returned from wms_get_user_meta, $post_id);
That would explain why your 7 is always at the end of your data.
I would take a look at the mws_get_user_meta function and make sure you are sending the right arguments. The core requires 3 arguments and I suspect your class' function does as well. Here is the core function:
function update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {
return update_metadata( 'user', $user_id, $meta_key, $meta_value, $prev_value );
}
Note that $user_id, $meta_key, $meta_value are all required or it will return false.
I have a custom post type crm, and i need to send a mail after each crm saved or updated. i user cmb2 for some custom meta like subject, to users etc. I know the save_post hook fires after post save (according to WordPress codex) in my case when i call save_post with two parameters (id and post) the post does not contains update values. here is my code :
function send_mail_to_user($id, $post){
$crm = $post;
$user_email = array();
if($crm->vc_all_vc == 'on'){
$args = array('orderby' => 'display_name');
$wp_user_query = new WP_User_Query($args);
$authors = $wp_user_query->get_results();
if (!empty($authors)) {
foreach ($authors as $author) {
array_push($user_email , $author->user_email );
}
}
}
else{
$to_users = $crm->vc_users;
$to_program = $crm->vc_program;
$to_group = $crm->vc_group;
$to_excode = $crm->vc_ex_code;
foreach ($to_users as $key => $value) {
$user_data = get_userdata($value);
array_push($user_email, $user_data->user_email);
}
foreach ($to_program as $key => $value) {
$users = get_users( array('meta_key' => 'programs' ) );
if($users){
foreach ($users as $index => $data) {
if(in_array($value , explode('#', $data->programs))){
if(! in_array($data->user_email, $user_email) )
{
array_push($user_email, $data->user_email);
}
}
}
}
}
foreach($to_group as $group) {
$term = get_term_by('slug', esc_attr($group), 'user-group');
$user_ids = get_objects_in_term($term->term_id, 'user-group');
foreach($user_ids as $user_id){
$fc_user = get_userdata($user_id);
if(! in_array($fc_user->user_email, $user_email) )
{
array_push($user_email, $fc_user->user_email);
}
}
}
foreach($to_excode as $codes) {
$value = explode('*',$codes)[1];
$users = get_users( array('meta_key' => 'programs' ) );
if($users){
foreach ($users as $index => $data) {
if(in_array($value , explode('#', $data->programs))){
if(! in_array($data->user_email, $user_email) )
{
array_push($user_email, $data->user_email);
}
}
}
}
}
}
foreach($user_email as $index => $email){
$to = $email;
$subject = $crm->vc_subject;
$body = $crm->post_content;
$headers = array(
'Content-Type: text/html; charset=UTF-8'
);
wp_mail($to, $subject, $body, $headers);
}
}
add_action( 'save_post', 'send_mail_to_user', 10, 2 );
And i also try publish_post hook , that works fine when new post created but when updated it works same. I have tried edit_post and post_updated hook also, but i never be able to retrieve my update data.
So how can i solve it? which action hook will give me all the new data?
thanks in advance.
You can use something like this,
function your_custom_function($meta_id, $post_id, $meta_key='', $meta_value='') {
if($meta_key=='_edit_lock') {
// if post meta is updated
}
}
add_action('updated_post_meta', 'your_custom_function', 10, 4);
Try with post_updated and use $post_after object.
https://codex.wordpress.org/Plugin_API/Action_Reference/post_updated
you can use this save_post hook with your function. change your hook priority to 100 it will give you updated post
add_action( 'save_post', 'send_mail_to_user', 100, 2 );
This might be a bit old but just wanted to give an update since from version 5.6.0 a new hook is available. The hook is wp_after_insert_post and you can find more information here . This hook is triggered after a post is created or updated and all of its terms and meta are updated. You can find an example below:
add_action( 'wp_after_insert_post', 'send_mail_to_user', 90, 4 );
/**
* Callback to: 'wp_after_insert_post'
* Fires once a post, its terms and meta data has been saved
* #param int $post_id Post ID.
* #param WP_Post $post Post object.
* #param bool $update Whether this is an existing post being updated.
* #param null|WP_Post $post_before Null for new posts, the WP_Post object prior to the update for updated posts.
*
*/
public static function sync_product_registrations_on_update( $post_id, $post, $update, $post_before ) {
if ( 'post' !== $post->post_type ) {
//Only to process the below when post type is 'post' else return
return;
}
if ( ! in_array( $post->post_status, [ 'private', 'publish' ] ) ) {
//To only process when status is private or publish
return;
}
//The rest of your code goes here
}
You can use the rest_after_insert_{$this->post_type} hook (where $this->post_type is replaced with the post type, eg 'post' or 'myposttype').
Thanks to Florian Brinkmann for this link.
add_action('rest_after_insert_myposttype', 'myfunction', 10, 3);
function myfunction($post, $request, $creating) {
// $creating is TRUE if the post is created for the first time,
// false if it's an update
// ...
}
See also here.
Some workaround is to use $_POST['meta_field'] with sanitation:
$to_users = $_POST['vc_users'];
$to_program = $_POST['vc_program'];
$to_group = $_POST['vc_group'];
$to_excode = $_POST['vc_ex_code'];
$to_users = sanitize_text_field($to_users);
$to_program = sanitize_text_field($to_program);
$to_group = sanitize_text_field($to_group);
$to_excode = sanitize_text_field($to_excode);
Pay attention to the field names, using ACF will make you use the field key.
This problem is more complicated than seems on first sight:
Our 'post_updated' hook is running before post is updated, so every attempt for getting meta data will result with the previous data. Also, Wordpress (v5.7.2) doesn't seem to have a hook for after a post was saved.
Also, 'save_post' hook is very complicated because it runs for every post saved or created including revisions and the $update boolean is still not reliable enough.
The correct and simpler answer is to use the wp_insert_post action.
https://developer.wordpress.org/reference/hooks/wp_insert_post/
An important distinction of wp_insert_post action is that it is fired
after update_post_meta has been called.
There are 3 parameters available - the $update flag tells you if this is a new or updated post.
do_action( 'wp_insert_post', int $post_ID, WP_Post $post, bool $update )
So - to implement your code after all post meta has been updated, use something like this:
add_action('wp_insert_post', 'run_after_post_updated', 10, 3);
function run_after_post_updated($post_ID, $post, $update ) {
// ...
}
You can use the save_post action wih a higher priority so that your function is called afer all meta data has been saved.
add_action( 'save_post', 'action_woocommerce_update_product', 20, 3 );
Here I have used higher priority 20
I'm trying to update a variable that is getting recieved by a session. Now it will save the data but it is for every post the same. It needs to save the value by post id.
A part of the code is (it's part of a Advanced Custom Field template):
<?php
function create_field( $field )
{
$value = $_SESSION['updatevalueMax'];
echo '<div id="value">' . $value . '</div>';
}
function update_value( $value, $post_id, $field )
{
return $value;
}
?>
The update_value function is activated when a post is updated. How to make this work so the $value is updated by $post_id? Thanks.
You will need to register the filter with Wordpress:
function my_plugin_update_value( $value, $post_id, $field )
{
// Do something and update $value.
return $value;
}
add_filter('acf/update_value', 'my_plugin_update_value', 10, 3);
Although in your example $value is just going to be what is sent into the function. I am not sure what you trying to update it with.
You will need to write a filter in your functions.php
follow the url to better understand.
http://codex.wordpress.org/Plugin_API/Filter_Reference/wp_insert_post_data
When we add new post in wordpress, after supplying the post title, the slug is generated automatically. I need to edit that auto generation module so that i can add some arbitrary number in the end of the slug automatically. How to do it?
Don't use the hard-coded version that the OP used here. When he did that, there was not a filter available. More recently, since 3.3, a filter was added.
add_filter( 'wp_unique_post_slug', 'custom_unique_post_slug', 10, 4 );
function custom_unique_post_slug( $slug, $post_ID, $post_status, $post_type ) {
if ( $custom_post_type == $post_type ) {
$slug = md5( time() );
}
return $slug;
}
However this method will change the slug every time you save the post... Which was what I was hoping for...
EDIT:
This kind of works for limiting the generation to just once. The only drawback is that it creates one version when ajax runs after creating the title, then it creates another, permanent slug when the post is saved.
function custom_unique_post_slug( $slug, $post_ID, $post_status, $post_type ) {
if ( $custom_post_type == $post_type ) {
$post = get_post($post_ID);
if ( empty($post->post_name) || $slug != $post->post_name ) {
$slug = md5( time() );
}
}
return $slug;
}
Write a plugin to hook into the wp_insert_post_data filter so you can update the slug before the post is sent for insertion into the database:
function append_slug($data) {
global $post_ID;
if (empty($data['post_name'])) {
$data['post_name'] = sanitize_title($data['post_title'], $post_ID);
$data['post_name'] .= '-' . generate_arbitrary_number_here();
}
return $data;
}
add_filter('wp_insert_post_data', 'append_slug', 10);
Note that this function requires that you allow WordPress to auto-generate the slug first, meaning you must not enter your own slug before generating, and it cannot update existing posts with the number.
Test this : (paste it into functions.php)
function append_slug($data) {
global $post_ID;
if (!empty($data['post_name']) && $data['post_status'] == "publish" && $data['post_type'] == "post") {
if( !is_numeric(substr($data['post_name'], -4)) ) {
$random = rand(1111,9999);
$data['post_name'] = sanitize_title($data['post_title'], $post_ID);
$data['post_name'] .= '-' . $random;
}
}
return $data; } add_filter('wp_insert_post_data', 'append_slug', 10);
add_filter('post_link','postLinkFilter', 10, 3);
/**
* Manipulates the permalink
*
* #param string $permalink
* #param stdClass $post
* #return string
*/
function postLinkFilter($permalink,stdClass $post){
return $permalink.'?12345';
}
Untested in that scenario, but I have already used it, should work with a minimum of changes, but try and test it REALLY Carefully .
In any Case, don't use rand() here or something alike, since the function must return the same link for the same post every time, otherwise you will have some serious problems.
Have fun!
You should operate with wp_ajax_sample-permalink action and name_save_pre filter.
More examples here: https://wordpress.stackexchange.com/a/190314/42702