Skip Navigation

[Resolved] Continued – Save avg of child cpf to parent radio cpf to allow searching

This support ticket is created 7 years, 10 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
- 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 -
- 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 -

Supporter timezone: Asia/Hong_Kong (GMT+08:00)

Author
Posts
#408557

Hi, I am referring to this previously resolved support thread:
https://toolset.com/forums/topic/save-child-review-rating-avg-to-parent-book-radio-field-to-allow-searching/

Luo helped me with a 'cred_save_data' function that would average all the CPF's called 'rating' of a child CPT called 'review' and then write that to a CPF 'average-review' of the parent 'CPT'.

This was so the parent posts could be parametrically searched for by the average value of one of their child fields.

After Luo helped me and the function was working I made a terrible terrible mistake and messed up my functions.php file without having made a copy of the working function.

(please don't ask - I don't want to relive the moment, it's giving me nightmares lol)

However according to Luo's support post in the thread above, the change he made to my function was very minor:

I quote:

"Thanks for the details, I have modified the PHP codes from:

$parent_id = get_post_meta($post_id, '_wpcf_belongs_' . $parent_slug . '_id');

To:

$parent_id = get_post_meta($post_id, '_wpcf_belongs_' . $parent_slug . '_id', true);

Please test again, check if it is fixed.

More help:
https://developer.wordpress.org/reference/functions/get_post_meta/
$single
(bool) (Optional) Whether to return a single value.
Default value: false"

I had my backup from immediately prior to giving Luo access, so I reverted to the backup and then made the change that Luo mentioned above.

However the fix doesn't work.

So I would like to ask Luo if perchance there was any other minor correction that he made that slipped his mind?

Terribly embarrassing and such a school-boy error.

Thanks

Jeff

#408691

Following with interest.
Jeff and I are going to have to throw a little party when we finally get this working 🙂

Alan

#408832

Dear Jeff,

In your PHP function, you will need to update the custom field value first, then end with return function, so you will need to replace these lines from:

        return $res;

        update_post_meta($parent_id, 'wpcf-' . $average_field_slug, $res);

To:

        update_post_meta($parent_id, 'wpcf-' . $average_field_slug, $res);
		
        return $res;

Please let me know if you need more assistance for it.

#409321
Beak & Claw Back End Averages.png
Beak & Claw Front End Averages.png
A New Day front end averages.png
A New Day Back end averages.png
TekWar Front end averages.png
Tek War Back End Averages 1.png
Tek War Back End Averages 2.png
Crimson Front End Averages.png
Crimson Back End Averages 1.png
Crimson Back End Averages 2.png
Unmuzzled back end averages.png
Unmuzzled front end averages..png

Hey Luo, thanks for your continuing support,

So I adjusted the code as above, but it still wasn't writing to the parent field. However it got me looking at the maths again.

What I did was simplify the averages and added 'lower than or equal to' operators. I also valued the averages at 0 prior to the calclulation, matching the averaging shortcode function from where I got this maths.

My 'cred_save_data' action now looks like this:

<?php
add_action('cred_save_data', 'save_average_review_rating_to_parent_book',10,2);
function save_average_review_rating_to_parent_book($post_id, $form_data) {
    if ($form_data['id']==250) {
        $parent_slug = 'book'; // parent post type slug
        $child_slug = 'review'; // child post type slug
        $rating_field_slug = 'rating'; // the rating field slug in child post
        $average_field_slug = 'average-review'; // the average rating field slug in parent post
        $parent_id = get_post_meta($post_id, '_wpcf_belongs_' . $parent_slug . '_id', true);
        $child_posts = types_child_posts($child_slug, array('post_id' => $parent_id));
        $sum = 0;
        $num = 0;
        foreach ($child_posts as $child_post) {
            if(isset($child_post->fields[$rating_field_slug]))
            {
                $sum += $child_post->fields[$rating_field_slug];
                $num ++;
            }
        }
        $average = 0; //Added this, taken from the averages shortcode below
        if($num>0)
        {
        $average = $sum/$num;
        }
        $res = $average;
        if($average==0) $res = 0;
        if($average>0.001 && $average<=0.5)$res = 0; //Added <=
        if($average>0.501 && $average<=1.5) $res = 1;
        if($average>1.501 && $average<=2.5) $res = 2;
        if($average>2.501 && $average<=3.5) $res = 3;
        if($average>3.501 && $average<=4.5) $res = 4;
        if($average>4.501 && $average<=5) $res = 5;
        //... here put more condition ...        
	
	update_post_meta($parent_id, 'wpcf-' . $average_field_slug, $res);		
        
	return $res;
    }
};
?>

The good news is that it is now writing to the database, which is fantastic! (And this time I backed up immediately lol)

However, because my averages shortcode is using half stars I decided to replace the arithmetic in the shortcode function so that it matches the above.

I wanted to keep displaying the shortcode average, because I know it works and I could use it to check against the average being written to the parent upon submission of a review.

So now my average review shortcode function is as follows:

<?php
add_shortcode('rating-average', 'rating_average_func');
function rating_average_func() {
    global $post;
    $args = array(
        'post_type' => 'review',
        'meta_key' => '_wpcf_belongs_' . $post->post_type . '_id',
        'meta_value' => $post->ID,
    );
    
    $child_posts = get_posts($args);
    $sum = 0;
    $num = 0;
    foreach ($child_posts as $child_post) {
    $rating = get_post_meta($child_post->ID, 'wpcf-rating', true);
    if($rating)
    {
    $sum += $rating;
    $num ++;
    }
    }
    $average = 0;
    if($num>0)
    {
    $average = $sum/$num;
    }
    $res = $average;
    if($average==0) $res = 0;
    if($average>0.001 && $average<=0.5)$res = 0;
    if($average>0.501 && $average<=1.5) $res = 1;
    if($average>1.501 && $average<=2.5) $res = 2;
    if($average>2.501 && $average<=3.5) $res = 3;
    if($average>3.501 && $average<=4.5) $res = 4;
    if($average>4.501 && $average<=5) $res = 5;
    //... here put more condition ...
    return $res;
};
?>

As you can see, the arithmetic now matches, just differing in how to call the child post.

However there is a problem somewhere in my first 'cred_save_data' arithmetic. I can see this in the discrepancy between the output of the shortcode and the value being written to the parent custom field upon submission of my review form.

Please see the screenshots.

In the screenshots, you can see that the shortcode is returning correct averages on the front end.

However in the back end, the custom field is showing incorrect averages.

As best I can tell, the back end is summing the averages without including the average from the review form that activates the 'cred_save_data' action.

The funny thing is, that as more reviews are submitted this problem will become unnoticeable, as the averaging function itself, combined with the high rounding tolerances (no half stars) will smooth out this problem. I only noticed it because I have deleted most of the reviews to test the function. Once there are even 5 or 6 ratings the averaging function returns the correct star rating. (as you can see from the TekWar & Crimson screenshots)

Having said that, my OCD is screaming and initial beta users will be important.

Can you see where I am going wrong? Should I be using a 'Cred_before_save_data' action? Or is it purely an php arithmetic mistake?

Ever grateful for any insight and direction.

Jeff

#409562

Thanks for the details, since it is a custom PHP codes problem, please duplicate same problem in a test site, and fill below private detail box with login details and ftp access, also point out the problem page URL and where I can edit your custom PHP codes, I need a live website to test and debug, thanks

#409637

I noticed it doing that too Jeff, and guessed that it was because the initial state of my submitted review posts is "draft".
I've not tested this hypothesis, and don't know if that's how it works.
As you say, over time, as the number of reviews increases, it would become less of an issue.

#409680

Hey Alan,

Yeah, I initially wondered if it was because of the draft status, however while the review posts were still drafts I could see their ratings under the relationship field in the parent Books, so the data had been written to the database.

When I thought about the sequence, it sort of makes sense that the arithmetic function would do the maths based on the data already written to the database upon submitting a new review, and since that new review hadn't yet been written to the database (in process as it were), it wouldn't be included in the function.

I am hoping that I'm wrong, or there is a way around this, as my partner who is generating content has his mind (stubbornly) set on actually using a larger scoring range, from 1 to 10 instead of 1 to 5. I believe this larger range would result in it taking longer for the misscoring to be smoothed over, smaller increments and less rounding etc.

Jeff

#409798

Hi Luo

I need to delay your support helping me debug this code.

I have another support ticket with Beda:
https://toolset.com/forums/topic/assigned-parents-deselecting-when-publishing-post/#post-409792

Regarding the de-assigning of post parents during the publishing process of draft posts.

Beda has another report of this problem and it seems a higher priority than my specific issue, being general to the overall operation of Types and Views.

I am going to backup my site, follow the debugging instructions provided by Beda to collect information for him, so I'll need to deactivate plugins, themes, reinstall toolset and collect wp/toolset debugging info and console errors.

I only have a few hours till the next leg of my trip, so I'll get onto this now, get the data to Beda and then restore my backup so that everything is as it stands for this support thread.

I will send another message when I'm done.

#409956

OK, Please update this thread when your test site is ready for debug, thanks

#412804

Hi Luo,

I have reset my test site to the previous backup.

As best I can tell, the 'cred_save_data' action arithmetic is averaging the ratings scores from only previously submitted reviews and posting that to the parent post average rating field, without including the rating from the current review CRED form. (the one creating the action)

Thanks for all your help.

Jeff

#412805

Hi Luo,

I have reset my test site to the previous backup.

As best I can tell, the 'cred_save_data' action arithmetic is averaging the ratings scores from only previously submitted reviews and posting that to the parent post average rating field, without including the rating from the current review CRED form. (the one creating the action)

Thanks for all your help.

Jeff

#412891

Thanks for the details, I am checking in your website, will feedback if there is any found.

#413315

Hi Luo,

I have fixed the arithmetic, I believe it is working now.

I had a look again with fresh eyes after my break, and revisited Alan's support thread and Beda's arithmetic and function here:

https://toolset.com/forums/topic/saving-a-rating-average-score-to-a-parent-post-to-enable-filtering/#post-365808

and combined the necessary elements.

With regards to the averaging function, I started my sum value (combined value of all the review ratings values for a book) from the value of the current cred form rating field thereby including it in the averaging math as I subsequently added each of the brother values:

$sum = get_post_meta($post_id, 'wpcf-rating', true); 

I started the num value from 1, to include the current cred form in the number by which to divide the amended sum value:

$num = 1;

So now my total function is as follows:

<?php
add_action('cred_save_data', 'save_average_review_rating_to_parent_book',10,2);
function save_average_review_rating_to_parent_book($post_id, $form_data) {
    if ($form_data['id']==250) {
        $parent_slug = 'book'; // parent post type slug
        $child_slug = 'review'; // child post type slug
        $rating_field_slug = 'rating'; // the rating field slug in child post
        $average_field_slug = 'average-review'; // the average rating field slug in parent post
        $parent_id = get_post_meta($post_id, '_wpcf_belongs_' . $parent_slug . '_id', true);
        $child_posts = types_child_posts($child_slug, array('post_id' => $parent_id));
        $sum = get_post_meta($post_id, 'wpcf-rating', true); // Start sum from the value of this post forms rating score
        $num = 1; //This posts to be added to the total review post count for the averaging arithmetic
        foreach ($child_posts as $child_post) {
            if(isset($child_post->fields[$rating_field_slug]))
            {
                $sum += $child_post->fields[$rating_field_slug]; 
                $num ++;
            }
        }
        $average = 0; //Added this, taken from the averages shortcode below
        if($num>0)
        {
        $average = $sum/$num;
        }
        $res = $average;
        if($average==0) $res = 0;
        if($average>0.001 && $average<=0.5)$res = 0; //Added <=
        if($average>0.501 && $average<=1.5) $res = 1;
        if($average>1.501 && $average<=2.5) $res = 2;
        if($average>2.501 && $average<=3.5) $res = 3;
        if($average>3.501 && $average<=4.5) $res = 4;
        if($average>4.501 && $average<=5) $res = 5;
        //... here put more condition ...        
     
    update_post_meta($parent_id, 'wpcf-' . $average_field_slug, $res);      
         
    return $res;
    }
};
?>

Alan, it seems to be working for me, I've tested it 4 times now and the averages are all correct, it displays the exact average as the shortcode averages.

Luo thank you for all your help, you've been great, if you're chatting to Beda give him my thumbs up too. I am going to leave this unresolved until I hear back from you, just incase you spotted anything else while you were having a look.

Very Chuffed. 😀

Jeff

#413348

I checked in your website, see the problem CRED form ID 250:
hidden link
in section "Post Type Settings", option "Select the status of content created by this form:" is "Pending Review", but in the PHP codes, your theme/functions.php, line 172~177:

...
    $args = array(
        'post_type' => 'review',
        'meta_key' => '_wpcf_belongs_' . $post->post_type . '_id',
        'meta_value' => $post->ID,
    );
    
    $child_posts = get_posts($args);
...

It will only include the posts which is in "Published" status, see wordpress document:
https://codex.wordpress.org/Function_Reference/get_posts
'post_status' => 'publish',

If you count the review into the shortcode [rating-average] after the user submit the review post at once, you will need modify above PHP codes to:

...
    $args = array(
        'post_type' => 'review',
        'post_status' => 'any',
        'meta_key' => '_wpcf_belongs_' . $post->post_type . '_id',
        'meta_value' => $post->ID,
    );
    
    $child_posts = get_posts($args);
...
#413360

Understood, and bonus lesson. Thanks again Luo, really appreciated mate!

Jeff

This ticket is now closed. If you're a WPML client and need related help, please open a new support ticket.