Support

Account

Home Forums Search Search Results for 'save limit'

Search Results for 'save limit'

reply

  • I cannot think of any easy way to do this.

    I would create the CPT and then I would create a function that did this that I would remove when the process is complete.

    I would also set the options page auto_load argument to true and save the options page, this alone might speed up the loading of the options page. But you need ti to auto load for the conversion.

    Next thing is that I would create a new text field in the repeater called “tranfered_to_post” or something like that, name does not really matter. Again, save the options page to and this will make sure the new sub field exists in all of the rows.

    
    add_action('init', 'move_repeater_to_cpt');
    function move_repeater_to_cpt() {
      // set some reasonable limit on the number of posts to create
      // to prevent timeout
      $limit = 20;
      // count of posts created
      $count = 0;
      if (have_rows('repeater', 'options')) {
        while(have_rows('repeater', 'options')) {
          the_row();
          if (!empty(get_sub_field('tranfered_to_post')) {
            // this row already done, move to the next one
            continue;
          }
          // *********************************************
          // create a new post base on row data
          // *********************************************
         
          // mark the row as done
          update_sub_field('tranfered_to_post, 'done');
        } // end while have_rows
      } // end if have_rows
    } // end function
    

    then you just need to keep reloading any page on the site until all of the rows are converted. Then delete the function.

  • I did that but for some reason it made the field disappear. What I really want to do is to strip non-numeric characters before it is submitted.

    I looked at this forum thread that you previously answered before John: https://support.advancedcustomfields.com/forums/topic/limit-field-value-to-letters-only-with-no-numbers/ and it did not work. This is what I did:

    1. I placed this code into the __construct function of the main plugin php file (the php file with the same name as the plugin). This is the code:

    add_filter(‘acf/validate_value/name=sell_price’, ‘allow_only_floats’, 20, 4);
    add_filter(‘acf/validate_value/name=buy_price’, ‘allow_only_floats’, 20, 4);

    function allow_only_floats($valid, $value, $field, $input) {
    if (!$valid) {
    return $valid;
    }
    if (preg_replace(‘/[^0-9.]/’, $value)) {
    return ‘Only numbers are accepted’;
    }
    return $valid;
    }

    2. When I put in non-numeric characters, it was still being saved with those non-numeric characters.
    3. I’m not really sure what the “20” and “4” values mean, but I just copied it from your previous form post.

    Where could I go from here?

  • Thanks again!!

    If I choose option to make the number field conditional based on the radio field, and I choose defaut value of 10 000, will that specific value be saved in database if unlimited is choosen (and number field hidden)?

  • A number field.

    Assuming that you have a range of 1 to 9999 before unlimited and you want unlimited to be sorted as highest then you would represent unlimited with 10000.

    At least that’s the way I’d do it.

    Or if I was going to make it easy for the client I would have a radio field to select “unlimited” or “set limit” and then a number field to allow setting the limit with a max value. This number field would be conditional based on the radio field. Then I would create an acf/save_post action that would set this number field to 10000 if the radio field was set to unlimited making unseen by the user.

  • Reading in 10k posts and then looping over them will likely cause other issues with performance due to the data returned in the query and memory.

    The biggest issue to speed is that regex on the date and the number of fields your using to filter.

    If I needed to do something similar to this and knew it before I started I would have a separate field (not in ACF, just your standard WP custom meta field). I would create and acf/save_post filter. In this filter I would get the date field, extract the year and save just the year into this other field. The I could do a simple ‘==’ compare on this field. This would greatly improve the performance of the query.

    But with 10k posts to look at it might still be a little slow. If it was I would likely use WP transients to store the results of the query for a time. This would mean the query would only need to be run once every few days.

    You could also have a taxonomy for the year, as in one of the points you listed, with the right settings you can actually hide this taxonomy. Instead of saving the year in another fields as in my first suggestion the acf/save_post filter would set the correct term in the year taxonomy.

    Post meta can be used for filtering, however, the filtering needs to be limited and the use of things like “LIKE” and “REGEXP” are going to cause performance issues.

    I also have one site, this site has “Products” and there are (no lie) 18 different filters used on this site. Trying to filter by 18 custom fields would simply time out the load of the page. In this case, when a new “Product” is saved a CRON is triggered. This CRON runs through all of the possible values for every filter and stores the results. On the front end of the site I use this information to query the posts.

    Use a WP option, lets call this option “birth_years”. This option would be an array with this architecture.

    
    $birth_years = array (
      // each element of this array is "YEAR" => array()
      "2020" => array (
        // each element of this array is a post ID of a person in this year
        1, 2, 3, 4, 5
      )
    );
    

    Create an acf/save_post filter with a priority of 1 so that it runs before ACF saves the value of the date field. See the doc for this filter. In this filter I would compare the old value with the new value. If it is the same I would do nothing. If it is different I would get the option, remove this person’s post ID from the old year and add it to the new year in my array.

    Then when doing the query for people in the same year I would get the option add this to my query

    
    'post__in' => $birth_year['2020']
    

    completely eliminating the meta query.

    Hope some of this information helps you

  • Most of what I’m going to say will likely not help you unless you do a lot of work to make it happen.

    A repeater does not store a single value. It creates an entry in the options page for the repeater + an ACF field key reference for the repeater + an option & field key reference for each sub field in each row in the repeater. So let’s say that you have a repeater with 5 sub fields and 100 rows, the total entries in the db will be 5(subfields) * 2 * 100(rows) +2(the repeater) = 5002 options table entries for the repeater. Every call by ACF to get_option() produces multiple queries. To make matters worse, when calling get_fields('options') acf will load every options value it has ever stored for every options page.

    Ways to mitigate many queries for options, most of this needs to be done before a lot of data is input

    1) set autoload to true for the options page

    2) use a custom post ID for your options page like “my-custom-options-slug”. When you do this you will limit the queries for “get_fields()” to a limited number of db entries. The reason is that the “option_name” in the DB will be prefixed by this slug. Otherwise every “option” saved by ACF will be retrieved no matter what options page they are associated with. This is not something that can be done after data is entered because you need to enter it all again.

    3) An alternate to #2 is to use a post ID value for the options page post ID setting. This causes ACF to save the values in the meta table for a post instead of in the options page making it possible to do a single query for meta values instead of a single query for each value. This has the same downside as #2 after a lot of data is entered into the options page.

    4) You could likely reduce the number of queries on your existing data by not using get_fields() for options and instead use a repeater loop and get specifically what you want. This will limit the number of queries because ACF is not attempting to load every option value saved on every options page. This will help if you have many other options values other than those associated with the repeater.

    5) You can also limit the number of queires by using get_field('repeater-field-name', 'options') as this will cause ACF to only get the fields associated with the repeater, again, instead of trying to get every option value ever saved.

    6) A way to mitigate this issue after the fact would be to use transients https://developer.wordpress.org/apis/handbook/transients/. You can get the values and store the array in a transient so that then next time you can see if the transient has a value and skip doing the work. This way you can do one DB query to get the entire array.

  • Hi,

    Can someone please give some clear examples (or point me to an article) of why/when one would use ACF Gutenberg Blocks vs using regular ACF Fields (i.e. metaboxes)?

    Besides an obvious visual appeal of ACF Gutenberg Blocks, I can’t help but focus on the fact that Blocks store data as HTML comments in the post_content, while regular ACF fields store all data as separate entries in wp_postmeta. And that’s a pretty huge difference. So I want to understand all of the nuances, advantages & disadvantages of each method. Has anyone written a detailed article with a breakdown of each method, when/where it’s appropriate to use them and what limitations each method has?

    I already can think of a few issues, but maybe I am missing some, so I want to reference other people’s opinions.

    For example:

    1) When it comes to Blocks, it seems that they would be much faster at data retrieval by default. Because the data is stored as one big “blob” inside post_content. Which means that there is theoretically only 1 database query to get all of the content & custom field data. So that means that if you intend to have complex pages with lots of ACF fields, you should use Blocks. So that’s a clear advantage over regular meta fields.

    Or is it? Because yes, if you use regular ACF fields and a default ACF get_field() function, that would query wp_postmeta for each piece of data separately. Which is bad (possibly even very bad). But if you use `<a href=”https://developer.wordpress.org/reference/functions/get_post_custom/”>get_post_custom()</a&gt; you’ll get all of the postmeta data at once and not suffer any performance punishment whatsoever (since that function also caches data, so it’s lightning fast for each consecutive request).

    So seems like performance-wise both can achieve the same results. Or am I wrong?

    <strong>2)</strong> Blocks seem to have a downside to storing all of the data inside post_content, because (a) I can’t easily query that data from another page/post and (b) individual custom fields are not de-coupled from post content. I’ve read the Q&A that said that I can “load the post_content of a given post, and then parse the blocks using the parse_blocks() function” which seems reasonable, but how efficient is it? Also, if I wanted to pull a dozen pages somewhere, based on a matching meta field value, that would be pretty easy & “cheap” (resource-wise) to do with a custom WP_Query. What about doing it in Blocks? How expensive would it be? Would that be even possible? Seems like I’d have to pull ALL posts, loop through each one, run parse_blocks() on every post and only that way I’d find the ones with my desired custom field value. Seems like that would be super expensive & CPU time consuming to do.

    Or I am thinking about it completely wrong and my use-case for Blocks is completely inappropriate?

    <strong></strong>3)</strong> Another issue I can see is if data is hardcoded into post_content, does that mean that I can’t change a custom field output type (i.e. let’s say I want an ACF file field to now return attachment ID, instead of a URL). With regular fields, I can just use get_field('field_name', $post_id, true) and get the ID no matter what and manipulate it how I want. But if it’s saved in a Block as a URL, does it mean it’s hardcoded into the page and the only way to change it is for me to update the block template & then also manually update/re-save every page where it was used?

    I think most of these issues stem from my lack of understanding where I should be using Blocks vs Meta fields. Hope someone can enlighten me.

    Cheers,
    Alex

  • The taxonomy field has a bunch of options that, I suppose, impact the ability to search terms, namely:

    1. Create Terms: Terms typed into the field will be newly created and added to the taxonomy (all the usual WP shenanigans attached, such as comma separation). You might not find terms, because they are being registered. Please check if previous searched have resulted in any data garbage being added to the taxonomy.
    2. Save Terms: Terms typed into the field will be added to the post itself be the usual means of WP. I venture that this will function only if the taxonomy itself is attached to the post type at hand. It might help to know what taxonomy we are dealing with.
    3. Load Terms: Terms typed into the field will be limited to the terms that have already been attached to the post. Basically, see 1 and 2.

    Which of these options, if any, are enabled?

  • Form process:

    <?php
    if (!defined('ABSPATH')) {
        exit; // Exit if accessed directly
    }
    
    acf_form_head();
    
    get_header();
    
    $car_edit = false;
    
    if (!empty($_GET['edit_car']) and $_GET['edit_car']) {
        $car_edit = true;
    }
    
    $restricted = false;
    
    if (is_user_logged_in()) {
        $user = wp_get_current_user();
        $user_id = $user->ID;
        $restrictions = st_get_post_limits($user_id);
    } else {
        $restrictions = st_get_post_limits('');
    }
    
    if ($restrictions['posts'] < 1) {
        $restricted = true;
    }
    
    $vars = array();
    if ($car_edit): 
      
        if (!empty($_GET['item_id'])) {
            $item_id = intval($_GET['item_id']);
        $vars = array(
            'id' => $item_id
        );}
    		endif;
     ?>
    <div>
    <form method="POST" action="" enctype="multipart/form-data" id="car_form">
    <?php if ($car_edit): ?>
    <input type="hidden" value="<?php echo intval($item_id); ?>" name="current_car_id"/>
    <?php endif; ?>
    
    <?php load_template('add_car/stp1', $vars); ?>
    ...
    <button type="submit" class="enabled" data-load="edit" >Save</button
    </form>
    </div>
    
    <?php
    get_footer();
  • If I was going to do something like this, starting at the beginning and knowing that I would be moving to a multisite setup……..

    I would start by setting up multisite and I would create a “master theme” where I would create all of the field groups. This master theme would have an acf-json folder so that when I made changes to a field group the changes would be saved in the json folder. Without doing this you would need to import the field groups to each them anyway, so you would not have a master location for maintaining all the field groups.

    I might actually create the acf-json folder in the root of /themes/ rather than in the theme and then use the custom save and load points in ACF to https://www.advancedcustomfields.com/resources/local-json/

    
    $path = dirname(get_stylesheet_directory()).'/acf-json';
    

    In each of the other themes I built I would create my own function to load the field groups that are needed for each theme from this master theme json folder using a variation of this https://github.com/Hube2/acf-filters-and-functions/blob/master/acf-load-parent-theme-field-groups.php&#8230; this was something that I created either before acf allowed multiple load points or before I realized they existed. I keep it around because it’s a good reference. I would only load the groups I needed, filtering by the group key.

    My goal would be to limit the number of places that these field groups existed and this would limit it to 1 locations and one place where they could be edited.

  • There really isn’t a way to do this simply.

    There are a couple of choices.

    The is to create an acf/save_post filter https://www.advancedcustomfields.com/resources/acf-save_post/. In this filter get the value of the field and save it as an option https://developer.wordpress.org/reference/functions/update_option/. Then create an acf/load_field filter https://www.advancedcustomfields.com/resources/acf-load_field/ and set the default value for the field based on the option.

    Second choice. Create an acf/load_field filter. In this filter you do a query to get the posts of the post type. Order DESC by the custom field, limit the posts returned to only get 1 post. Get the value of the field on this one post and set the default value of the field based on this value.

    Either has it’s pros and cons

  • I have made some test and it seems that ACF calls get_option() when the block inserted into the content does not actually contain the field keys predicted during registration via acf_add_local_field_group().
    It happens when I save an empty block or a block with hidden fields.

    So when I add an empty block which looks within the code like:

    <!-- wp:acf/header {"id":"block_5c8ac410e890e","name":"acf/header","align":"","mode":"edit"} /-->

    the plugin looks for the missing fields in wp_options table, for example:

    SELECT option_value
    FROM wp_options
    WHERE option_name = 'block_5c8ac410e890e_my-header-content'
    LIMIT 1

    where my-header-content is the name of a field type group in this case.

    It’s quite surprising for me – why ACF thinks that I store any block data in wp_options?

    Then, when I add some content into the subfield of my-header-content field, the plugin no longer queries wp_options for my-header-content and the block structure grows into:

    <!– wp:acf/header {“id”:”block_5c8ac410e890e”,”data”:{“field_my-header-content”:{“field_my-header-content-lead”:”This is our lead”,”field_my-header-content-text”:””},”field_my-header-aside”:{“field_my-header-aside-settings”:””},”field_my-header-background”:{“field_my-header-background-image”:””,”field_my-header-background-video”:””,”field_my-header-background-color”:”white”,”field_my-header-background-has-pattern”:”0″}},”name”:”acf/header”,”align”:””,”mode”:”edit”} /–>

    Well, after all I think I’ll report it on Github…

  • There isn’t any way to do this using a single field because the repeater will contain all of the existing rows and trying to limit this number of rows will cause issues. There isn’t a way to have one repeater that can be use to add new rows without showing all of the rows.

    To do this you would need to have 2 different fields, one repeater that is used in the admin and one that is used only on the front end.

    You can put your second field into a different field group.

    You can then specify the fields that you want to show when calling acf_form().

    When the front end field is loaded then you can add an acf/load_field filter, check the number of rows in the “real” repeater and limit the front end repeater based on that number.

    Then you create an acf/save_post filter. In this filter you transfer anything that’s in the front end repeater to the “real” repeater.

  • It is not possible to order the posts by a repeater sub field, so what you want to do is not possible. Even if it were possible, the nature of WP_Query would give you additional problems.

    Let’s say for example that “Show 1” is on “date 1” and “date 2” while “Show 2” is on “date 1” and “date 3”. Using WP_Query you will only see each “Show” listed once.

    
    Date 1
      => Show 1
      => Show 2
    
    Date 2
       Nothing listed, show 1 already shown
    
    Date 3
      Nothing listed, show 2 already shown
    

    I am actually currently working on a project that has a similar problem. The client wants “Events”. Each event can happen on multiple dates. Basically the same thing that you are doing. I have no choice but to use a repeater for this. How am I solving this.

    1) I’ve made my post type hierarchical.

    2) On top level posts I have a field group with the repeater. On child posts I have a field group that contains just a start date/time and an end date/time field. This requires a custom location rule.

    3) When an event is saved I have an acf/save_post action that creates creates and deletes child posts for the event based on the dates saved in the repeater field.

    4) In the admin list of posts I am hiding the child posts so that the client cannot see them. I am also hiding the fact that they can create child posts. I have a filter on pre_get_posts for this post type in the admin and I’m using ACF “hide on screen” to hide the page attribute blocks. So, basically, the client will never see the fact that all these posts are being added and deleted.

    I will post the relevant code for the above at the end of this.

    The remaining is not done. When showing posts on the front end I will do a pre_get_posts filter that will remove parent posts from the query and order all of the child posts by their start date/end date fields. When showing links I will link to the parent post instead of the child post. I’m probably also going to need to limit the number of dates that the client is allowed to add so that updating a post does not time out.

    The following code has not been made to work for your needs, it is just provided as as example of what I’ve done so far. The only thing that I’ve done is remove the client’s name from the code. It also has not been completely tested since I’m in the process of building it.

    
    <?php 
      
      class client_name_events {
        
        private $post_type = 'events';
        
        public function __construct() {
          add_action('pre_get_posts', array($this, 'hide_children_in_admin'));
          add_filter('acf/location/rule_types', array($this, 'acf_location_rule_types'));
          add_filter('acf/location/rule_values/post_level', array($this, 'acf_location_post_level_values'));
          add_filter('acf/location/rule_match/post_level', array($this, 'acf_location_post_level_match'), 20, 3);
          add_action('acf/save_post', array($this, 'save_event'), 20);
        } // end public function __construct
        
        public function hide_children_in_admin($query) {
          if (!is_admin() || !$query->is_main_query()) {
            return;
          }
          if (!isset($query->query_vars) ||
              !isset($query->query_vars['post_type']) ||
              $query->query_vars['post_type'] != $this->post_type) {
            return;
          }
          $query->set('post_parent', 0);
        } // end public function hide_children_in_admin
        
        public function save_event($post_id) {
          if (get_post_type($post_id) != $this->post_type) {
            // not our post type
            return;
          }
          $parent = wp_get_post_parent_id($post_id);
          if ($parent) {
            // this is a child post
            // this should never happen
            // it's only here to cover all bases
            return;
          }
          
          // get all dates from repeater
          $dates = array();
          if (have_rows('dates', $post_id)) {
            while (have_rows('dates', $post_id)) {
              the_row();
              $dates[] = array(
                'start' => get_sub_field('start'),
                'end' => get_sub_field('end')
              );
            }
          }
          
          // get list of existing date posts
          $existing_dates = array();
          // get all child posts
          $args = array(
            'post_type' => 'events',
            'post_parent' => $post_id,
            'numberposts' => -1,
          );
          $children = get_children($args);
          $new = array();
          $delete = array();
          if (!empty($children)) {
            foreach ($children as $id => $event) {
              $existing_dates[$id] = array(
                'id' => $id,
                'title' => $event->post_title,
                'start' => get_field('start_date', $id),
                'end' => get_field('end_date', $id)
              );
            } // end foreach children
          } // end if !empty children
          
          // create list of dates to add
          // loop over all $dates, and all $existing_dates
          // if a date does not exist add it to the list to be added
          $add = array();
          if (count($existing_dates)) {
            foreach ($dates as $date) {
              $found = false;
              foreach ($existing_dates as $existing_date) {
                if ($date['start'] == $existing_date['start'] && $date['end'] == $existing_date['end']) {
                  $found = true;
                  break;
                }
              } // end foreach existing date
              if (!$found) {
                $add[] = $date;
              }
            } // end foreach dates
          } else {
            // no existing dates
            // add them all
            $add = $dates;
          }
          
          // create list of dates to remove
          // loop over all existing dates and all dates
          // if a date does not exist then add it to list of dates to remove
          $remove = array();
          if (count($exisiting_dates)) {
            foreach ($existing_dates as $id => $existing_date) {
              $found = false;
              foreach ($dates as $date) {
                if ($date['start'] == $existing_date['start'] && $date['end'] == $existing_date['end']) {
                  $found = true;
                  break;
                }
              }
              if (!$found) {
                $remove[] = $id;
              }
            } // end foreach existing date
          } // end if existing dates
          
          // delete posts
          if (count($remove)) {
            foreach ($remove as $id) {
              wp_delete_post($id, true);
            }
          } // end if posts to remove
          
          // add posts
          if (count($add)) {
            foreach ($add as $date) {
              $post = array(
                'post_title' => $date['start'].' to '.$date['end'],
                'post_type' => 'events',
                'post_parent' => $post_id,
                'post_status' => 'publish'
              );
              $new_id = wp_insert_post($post);
              if ($new_id) {
                update_field('field_5c6eb7f6dc628', $date['start'], $new_id);
                update_field('field_5c6eb81ddc629', $date['end'], $new_id);
              }
            } // end foreach date to add
          } // end if posts to add
        } // end public function save_event
        
        public function acf_location_rule_types($choices) {
          if (!isset($choices['Other'])) {
            $choices['Other'] = array();
          }
          if (!isset($choices['Other']['post_level'])) {
            $choices['Other']['post_level'] = 'Post Level';
          }
          return $choices;
        } // end public function acf_location_rule_types
        
        public function acf_location_post_level_values($choices) {
          $choices['top'] = 'Top Level Post';
          $choices['child'] = 'Child Post';
          return $choices;
        } // end public function acf_location_post_level_values
        
        public function acf_location_post_level_match($match, $rule, $options) {
          if ($rule['param'] == 'post_level') {
            $post_id = $options['post_id'];
            $parent = wp_get_post_parent_id($post_id);
            if ($parent) {
              $level = 'child';
            } else {
              $level = 'top';
            }
          }
          switch ($rule['operator']) {
            case '==':
              $match = ($level == $rule['value']);
              break;
            case '!=':
              $match = ($level != $rule['value']);
              break;
            default:
              // do nothing
              break;
          }
          return $match;
        } // end public function acf_location_post_level_match
        
      } // end class client_name_events
      
    ?>
    
  • Hi,

    I received an email that tell that the user Feyfey answered my thread, however for a weird reason, I can’t see the post here.

    For my first question, I presume it was ok to said that ACF finally asigned an empty string (and not a null value) in the meta key. Maybe it happens when entering and removing a date manually in the field, then save the post. However I haven’t been able to make work the “NOT EXISTS” comparasion yet.

    For my second one, here’s finally a group of arguments which worked for me :

       $date_limit = date('Y-m-d', strtotime("-3 days"));
        $args = array(
            'post_type'      => 'vehicle',
            'meta_key'       => 'date_sell',
            'meta_query'     => array(
                'relation' => 'OR',
                array(
                    'key' => 'date_sell',
                    'compare' => '>=',
                    'value' => $date_limit,
                    'type' => 'DATE'
                ),
                array(
                    'key' => 'date_sell',
                    'compare' => '=',
                    'value' => ''
                )
            )
        );

    So with a Date type and ‘Y-m-d’ format.

    Hope it’ll help.

    Nox

  • See this https://www.advancedcustomfields.com/resources/limit-number-fields/

    Also, ACF can time out when there is too much data to be saved. This depends not only on the number of fields but what’s in those fields and how many queries need to be accomplished to do the saving. There is no fix for this. I suspect this may be part of the problem if you’re getting a blank page.

  • Ah, I’m glad it’s working now—apparently this functionality (or this filter?) is limited to Pro.

    I would start a new topic for your other request… I don’t know anything about Buddypress, but the user dropdown wouldn’t search that data unless it saved them as actual WordPress users. Best of luck! 🙂

  • This really is not to do with ACF, it is due to your limiting of seeing media files to the person that uploaded them.

    The the database description for WP here https://codex.wordpress.org/Database_Description

    An image, or other type of file is saved as an “attachment” post type in the posts table. When you limit a user to see only their media you are actually limiting them to see only their own post of this post type by the “post_author” column in the database. This column can only have one value and that value is the person that uploaded it.

    In order to allow another user to see these media files you would also need to duplicate all of the “attachment” “posts” and apply the new user ID to them. This would also mean duplicating the actual media files.

  • PROBLEM SOLVED! It was MY code. I missed the “=”. So I hade “max_input_vars 5000” when it should have been “max_input_vars = 5000”

    Plugin is now showing Field limit: 5000 and I a can save the nested repeater.

  • "save_post_{$post_type}" runs before "save_post". ACF does not set the values of the field until the second hook. So you are trying to get values from a field that has not been set yet. When you update the post the second time (and after) you are using values that were saved the previous time the the post was saved and it will not reflect changes correctly if the first image in the gallery has been changed.

    Whenever dealing with ACF you need to use the acf/save_post hook. https://www.advancedcustomfields.com/resources/acf-save_post/

    I know that you are trying to limit your filter to a specific post type, but you can do this in your acf/save_post filter

    
    add_action( 'acf/save_post', 'set_featured_from_gallery', 20);
    set_featured_from_gallery ($post_id) {
      if (get_post_type($post_id) != 'galleries') {
        return;
      }
      // code continues...
    }
    
  • For my custom field type I needed to get all values at once and the function update_value( $value, $post_id, $field ) only handles each field seperate. Because the Amazon Product Advertising API only allows

    … an initial usage limit of 1 request per second*.

    I had to find another way.

    So after a while I realized, that the only way to get all fields at once on save, is to hook into acf/save_post before it gets modified.

    I have to place a seperate action hook into __constructor() / initialize():
    add_action('acf/save_post', array($this, 'on_save_values'), 1);
    and then iterate over all fields of acf:

    function on_save_values( $post_id ) {
                // bail early if no ACF data
    	        if( empty($_POST['acf']) ) {
    
    		        return;
    
    	        }
    	        // array of field values
    	        $fields = $_POST['acf'];
                    
                    foreach($fields as $layouts){
                        //...
            }

    Maybe this helps anyone facing similar problems.

  • If this data already exists in a large quantity, doing what you want is not impossible, but in practice may not be possible.

    Here’s what would be needed. 1) Do a WP_Query() to get every thesis post and loop through these posts. 2) Get the relationship from each thesis post. 3) Loop though the values of the relationship field and keep track of the count of all relationships to each professor. 4) Sort the professors in order of the count of thesis posts 5) Query the professor posts and order by this order that you’ve created.

    With a limited amount of data the above is something that can be done. With a large amount of data the above is something that will likely cause performance issues on the page where it is done and could even potentially cause the page to time out.

    If the project is still at a point where you can make a significant change, this is what I would do.

    I would create an acf/save_post filter https://www.advancedcustomfields.com/resources/acf-save_post/ with priority set to 1 so that it runs before ACF saves the new value to the database. This filter would be for the thesis post where the relationship exists. I would create another post meta value attached to the professor post type that contains a count of all the thesis posts related to each professor. In the save_post filter I would look to see if any professors have been removed from the relationship, if they have I would get the count value from the professor, decrease the value and save it. I would then look to see if any professors have been added to the relationship field. If they have I would get the value from that professor, increase the count and save it. This would give you a field with a value that you can easily short the professors by. The only flaw I can see in this approach is the case where a thesis post is deleted, but you might be able to use a standard WP hook fired when a post is deleted to deal with this.

    There might be other solutions.

  • Basically, on this page https://www.advancedcustomfields.com/resources/query-posts-custom-fields/ if you look in the section 3. Multiple custom field values (array based values) it tells you how to query based on these values. I understand it and my advice is this, ignore it and don’t do it. Even if you get it to work if you add too many “LIKE” queries for the same meta key you’ll just end up timing out your site because of the limits of WP_Query.

    Instead make your life easier. You know that you can use an “IN” query with normal WP post meta fields, you already have an example of this. So instead of trying to search the ACF field, which is difficult, convert the ACF field into something that is easy to search.

    
    add_filter('acf/save_post', 'convert_classes_to_standard_wp', 20);
    function convert_classes_to_standard_wp($post_id) {
      // use a different field name for your converted value
      $meta_key = 'converted_classes';
      // clear any previously stored values
      delete_post_meta($post_id, $meta_key);
      // get new acf value
      $values = get_field('classes', $post_id);
      if (is_array($values) && count($values) {
        foreach ($values as $value) {
          add_post_meta($post_id, $meta_key, $value, true);
        } // end foreach
      } // end if
    }
    

    Now you can use converted_classes instead of classes in your meta query with the 'compare' => 'IN'.

  • If there is a problem with the values being saved then it is probably https://www.advancedcustomfields.com/resources/limit-number-fields/

  • I have been looking into a way to do this.

    Before I get into how this can be done, with some problems, I just want to point out that doing this the way that most people would expect it to be done is nearly impossible. If you know anything about the way ACF and WP work, and you’ve looked into this you’ll quickly come to the same conclusion.

    Sometimes “impossible” just means very difficult, but in this case it really does mean impossible. WP has limits to what it can do and attempting to have ACF clean up all unused values when they are no longer needed would run into these limits imposed by the way that WP is built. In almost all cases it would simply cause the saving and updating to time out and not complete.

    I would love to hear from people that use other custom field plugins an know if any of them clean up after themselves the way people want ACF to clean up after itself. I’d look myself, but I have no interest in these other plugins or seeing what happens with unused data.

    I’ve actually started trying to explain why it is impossible several times and failed. Trying to think about what needs to be done to have this automatically happen under every condition nearly makes my head explode.

    There is only one way I can think of that this can be done, and even it cannot be made to work under all conditions. That way is to delete all existing data before ACF updates the fields, or to just wholesale delete all content whenever an ACF field is deleted.

    The condition where this will not work is altering the location rules of a field group. If a field group is located on posts and you change the location to pages, there simply isn’t any easy way to then remove all of the field values from all of the posts that were already saved. Not without checking every object in WP to discover what objects the fields should not be saved for.

    There is also a condition that will cause data that you don’t want deleted to be deleted anyway. This condition will happen with cloned fields and in any other place where a field key is duplicated.

    There is also the case of someone deleting fields when the goal is to keep the field data because you want to move the fields into PHP and remove the field group from the ACF admin.

    I’ve actually started building a plugin that will do this, but I hesitate do complete it and make it publicly available because there are cases were, if used improperly, people will end up having content deleted that they do not want deleted and hold me responsible for messing up their site. While I know it will work if used properly, I’m afraid that there are probably too ways that it could be used improperly.

Viewing 25 results - 26 through 50 (of 148 total)