Home Forums Bug Reports field type link doesn't update


field type link doesn't update

  • I use link files quite a lot to link to internal (mostly) content. However when that content has a title/slug change the links are broken. Could this please use the ID to avoid this?

  • The link field uses the build in WP link insertion, the same thing that is used in the content area of the page. These links will break if the slug is changed the same way that links inserted into content will break if the slug is changed.

    My first suggestion would be to not changes slugs unless there is a very good reason to do so. Bad for SEO.

    My second suggestion would be to use a redirect plugin to add 301s when you need to change post slugs.

    My third suggestion would be to use a post object field instead of a link field.

  • Thanks john.

    Slugs will change dozens or even hundreds of times before a site is launched.

    Was trying to take advantage of the link label feature this field type has. This is used for external links too. Simpler for clients.

    Would be a smoother user journey and reduce the amount of fields if internal links could used the ID to keep links going to the intended page.

    best, Dan.

  • The issue is that the WP link input does not return the ID of the page for ACF to store. I’m not the developer, just a user that knows how it works. But since WP does not return a post ID… not really a lot that can be changed about what this field does.

  • I understand John but it would be a handy upgrade to the field. I’ll now have 3 fields whereas i thought i could just have one.

  • It might be a handy upgrade to the field, but… Elliot relies on existing functionality in many places. In this case he’s taking advantage of a popup that already exists and just storing the information that it returns. The link field is designed to work with any link, meaning it can be linked to something other than a post and in this case a post ID would not exist. To do this a new popup would need to be created at the minimum, different information would need to be stored like is it a post/term? Does it have an ID? if it does store the ID and if not then store the URL, format the return value differently based on this. More than likely this would mean a completely new field type that does everything that we can using a combination of several fields.

  • There’s no ‘but’ john. I”m not really sure what your point is. I don’t care about the details i’m just pointing out a possible improvement to this link field which i thought it already did.

    Simpler is better for everyone.

    I’ll write a function myself to insert local links with an ID so all of my links work indefinitely.

  • Sorry, you were reporting a bug. This isn’t a bug, it’s expected behavior. If you would like to submit a suggestion on this you should contact the developer

  • I experienced this problem today as well. A client updated the slug of some pages and now the links in some buttons weren’t working any more.

    The problem with the ‘post object’ and ‘page link’-fields is that they can’t be used for external links. I thought the ‘link’ field was ideal because it supports every thing, until this problem popped up..

    So for places where internal and external links can be used, we are forced to use:
    – a switch to choose between inserting an internal/external link
    – a post object or page link field for internal links
    – a url field for external links

    Is this really the best way? That’s a bit frustrating to set up and to code for.

  • I forgot to mention that we’ll also need extra fields for a label and activating “target=’blank'”.

    So for places where internal and external links can be used, we are forced to use:
    – a switch to choose between inserting an internal/external link;
    – a post object or page link field for internal links;
    – a url field for external links;
    – a switch to activate “target=’blank'”;
    – a text field for the label/text on a button/link.

    All of these could be replaced by using the link field, if only it’d update the actual url when a slug changes.

  • I don’t know if I said this before, but a page link field located in one place is not aware of changes to the slug for a page. The link field stores the current url when it is updated.

    This same thing will happen when you add a link in WP to the content area. If you create a link in the WYSIWYG using the WP add link filter you will experience the same issue of you then change the slug of the page you are linking to.

    ACF uses the built in WP link field and the ACF field is just a wrapper for WP functionality that already exists. In order to have the field and links updated when a slug is changed would require searching the content and all custom fields for every post to find the old link and replace it with a new link.

    The solution I employ is to install a redirect plugin, there are several available. I work at an SEO company and everyone here knows that when a URL on the site is altered that 301 redirect must be added. This is because in order to get search engines to index the new page instead of the old page that these redirects need to be put in place. A side effect of using a redirect tool is that these links that get broken by changing a slug do not result in a 404 page. My company also employs tool for our clients that scan internal links to find 404s and redirected pages so that these can be corrected later.

    Automating the updating of all links pointing to a page when a page slug is changed would be extremely difficult, if not impossible to achieve.

  • Hi John,

    Yes, you are right in stating that this is the default behaviour of WordPress.

    Not to be rude, but of course employees of an SEO company know that a slug shouldn’t be changed without thinking about it. The point is that the average client does not know this. Installing a redirection plugin and teaching the client how to use it could be a solution, but I think it doesn’t make things easier for anyone.

    For me the real problem is as described above: it’s a pity that we need to add 5 (!!!) fields to have a fool proof solution for having just a button with:
    – an internal/external link
    – label text
    – option to open in a new browser tab

    And as said, the code to implement such a button on the front end is way more complex then it would be when using the ‘link’ field since all the information is in one place and no switches are involved.

    The link option combines all these abilities, which is absolutely great. But it misses out in the case a slug is changed, while other fields like the ‘page link’ and ‘post object’ keep working because they use a post ID. I understand that this is the default WordPress implementation, but if that’s not good enough, ACF could consider building it’s own version. But if no one makes notice of the problem, it won’t happen. So that’s why I added my comment here.

    On a side note:
    I knew that WordPress sometimes redirects old slugs to the new ones, but I didn’t know how it exactly worked. You probably know this, but it might be interesting for other people. Apparently it’s being done by saving old slugs in the post-meta of posts, but only for posts that are non-hierarchical. (see:

  • I don’t know if this will help you or make your dev process any easier. My goal when I build a site has to do with making things easy for the client and not necessarily making it easier for myself, so when I’m building the admin for the client I don’t even give much thought to how difficult it will be for me to code, I just make sure that it’s something that can be coded. However, I do my best to never code something more than once.

    I build in “modules” I have a field group that has all the settings I need for links, not only the ones you mention but others. I then clone this field group as the only sub field of a “Group Field”, this insures that all fields of my group are always “sub fields” With this in place I have a single template part file that is called to output links.

    // something like this goes into my template
    if (have_rows('group_field_name')) {
      // always true for a group field that exists
      while (have_rows('group_field_name')) {
        // always executes once for group fields that exist

    So I have only coded this once. My group has become quite complicated, but if changes are made I only need to make them in a single file.

    The field group for links can also be cloned as the only sub field in a repeater and the template part file will still work but allow the client to add multiple CTA buttons.

    I actually use a true/false field the new window setting. The label on the true false field is
    – Same Window = false
    – New Window = true
    and the code in my template part for building this part of the link button is

    $target = '';
    if (get_sub_field('target')) {
      $target = ' target="_blank"';

    and example of my link output

    <a href="<?php echo $url; ?>" class="<?php echo implode(' ', $cta_classes) ?>"<?php echo $title.$rel.$target.$onclick; ?>><?php echo $text; ?></a>

    Also, when it comes to a URL and the client entering a URL, I do not use a URL field because it is too limiting. For example lets say that you want to allow the client to enter anything other than a URL. My clients and the people I work with want to be able to enter anchor links as well as tel:, mailto:, sms: and ftp: links. So instead of using a URL field I use a text field with custom validation. Building separate fields would increase the code and complicate things for the client. Instead I have a text field that will accept anything that appears to be a valid href value and as part of the client’s instruction when handing over the site they are shown how to use this field and the field has very good instructions to help remind them.

    add_filter('acf/validate_value/key=field_XXXXXXXX', 'validate_text_as_href', 20, 4);
    function validate_text_as_href($valid, $value, $field, $input) {
      // this allows links starting with
      // / (site root relative), http://, https://, ftp://, # (anchor), mailto:, tel:, sms:
      if (!$valid) {
        return $valid;
      if (!empty($value)) {
        if (!preg_match('%^(https?\://|ftp\://|/|#|mailto\:|sms\:|tel\:)%', $value)) {
          $valid = 'Enter a Valid HREF Value';
      return $valid;

    As to automatically updating or redirection, I have not built anything that will automatically redirect if the slug of a page is changed. I will need to look into that, what I do know is that what is built into WP rarely works as expected.

    As far as automatically updating links when a slug or url changes, you would need to keep some type of history on the slug/url of the page when it is updated. You would need to add a pre_post_update action that somehow checks to see if the url of the page is being changed. If it is then you’d have to figure out how to lookup and changed all of the other posts and pages where there is a link to the page being updated and change them without this process timing out the admin page refresh. This would basically mean that you’d have to record somewhere/somehow all of the places where a link to the page is saved to allow a quicker lookup so that they can be found quickly and updated.

    This brings me back to the automatic redirection because the testing to see if the URL has changed for a page sparked an idea. You could as in the above add a pre_post_update action and if possible record a history of all of the URLs that were ever assigned to this post and then on a 404 you could do a search for posts that have had the missing URL. This isn’t actually a bad idea that I may look into.

  • Hi John,

    Thanks for the extensive explanation. I can see that you really put a lot of thought into it.

    My first thought when you say that you’re using a module/template-part for something as small as a link, is that it seems like overkill. But it probably has pros and cons, I guess.

    We never went this far with components/template-parts and clone-able ACF option groups in our projects. It sure is an interesting approach and in the end it will probably save time, but it will take preparation to adopt it completely. We will consider it for future projects.

    Although this is a nice insight, I still feel like ACF has a plethora of possibilities to make the user input a link, and none of them is ideal. The ‘link’ type comes very close, but has a problem that ACF probably can’t solve because it’s WordPress core.

    Of course you can work around the problem by combining the 5 fields in a group and duplicating them wherever you want, but ACF is meant to make things simpler, right? This is a problem that every developer who works with ACF will need to tackle sooner or later. This feels like everyone has “to reinvent the wheel” while ACF could come up with a simpler solution.

    In my opinion it would probably be best if this problem would be addressed at the root, instead of somewhere along the line.

  • There is always the option of creating your own field type that has every option in it. There have been attempts to do this but they have all been short lived, meaning that after a time the authors stop maintaining them. But it the end it would not reduce the coding and could increase it. This question has been around and repeated for a long time. The main issue is that all the possibilities and use cases become a rabbit hole. To be honest, it would be impossible to encompass all of the options in my link group field into a single field.

    I have been building my system for some time, it does help to start on a new project. But it has evolved into a system that allows for the adding of CTA buttons to almost anything and there is a corresponding CTA button builder that allows clients to design CTA buttons and links. Yes, a template part could be seen as overkill for something as simple as a link, but it saves me a huge amount of time over re-codeing and I only have to make changes in a single location rather then hunt down all the places. I have not coded the showing of a link or CTA button in a very long time.

    ACF, while it can make things simpler, is a admin tool for building the admin UI. It’s goal is to make it easier and faster to build the UI for your client. ACF does not do anything that a developer cannot do without ACF using built in WP functions. Can you imagine the time it would take you to build a site if you had to build all of the UI parts that ACF lets you build, not to mention making it look as refined as an ACF field group. When Elliot built ACF the goal was to give us the tools to make the admin easier and free us from it so that we could devote our time to the front end of the site. I know that the linking seems like a PITA with all the different possibilities that you might need to incorporate.

    But all of this discussion does not fix the OP, that is of updating the urls in link fields. This is something that that is so complicated that even export/import tools to not replace hard coded URLs in content.

  • Let’s not forget that using the problem is not there when using option types like ‘post-object’ and ‘page-link’ because they don’t ‘hardcode’ the url to the database, but (probably?) use a filter to process the post ID when retrieving the value. The ‘url’ and ‘link’ fields hardcode the value to the database.

    I understand that there’s the possibility to create my own option type. I don’t have any experience with that for Advanced Custom Fields, but it’s a possibility. I can just be honest: I don’t have the knowledge to build something like that.

    But if you mention that this problem has been around for a long time and keeps coming back from time to time.. shouldn’t that be considered as a sign that it’d be a good idea for ACF to look into it more? Maybe a complete solution is possible?

    But well.. maybe WordPress will implement a solution on their own. The only real change that should be made is that internal links get saved with their ID instead of the plain url, and then process it when retrieving it.

  • I had a similar issue, found this thread, and just wanted to say @hube2 your solution of grouping/cloning/component-izing links like this is brilliant. Rolling it into my starter theme as soon as I’m able.

  • Maybe this might help someone, I’m attaching my configuration for a link-button. It offers variations for internal, external and on-page (anchor) links.

    Also, this is a function to output a link:

    function nij_output_link($atts, $class = '') {
    	if (!empty($atts)) {
    	$type = $atts['link_type'] ?? 'internal';
    	$url = '';
    	switch ($type) {
    		case 'internal' :
    			if (is_numeric($atts['link_' . $type])) {
    				// this is a post id and should be converted to a link
    				$url = get_permalink($atts['link_' . $type]);
    			} else {
    				// this is an archive link (and it should be left untouched)
    				$url = $atts['link_' . $type];
    		case 'external' :
    			$url = $atts['link_' . $type];
    		case 'onpage' :
    			$url = '#' . $atts['link_' . $type];
    	$target = $atts['link_target'] ?? '_self';
    	$text = $atts['link_text'] ?: (($type == 'internal') ? get_the_title($atts['link_internal']) : '');
    	$class = $class ?: '';
    	if (is_admin() && !empty($text)) {
    		$text = __('Knoptekst niet ingevuld', 'nijstartertheme');
    		$class .= ' disabled';
    	return "<a href='{$url}' class='{$class}' target='{$target}'>{$text}</a>";
  • Thanks @proxxim! Outputting the link via function could be helpful too.

Viewing 19 posts - 1 through 19 (of 19 total)

The topic ‘field type link doesn't update’ is closed to new replies.