Support

Account

Home Forums Feedback Change how the link field is stored in the database

Unread

Change how the link field is stored in the database

  • So here’s a scenario I run into far too often…

    I’m developing a site locally that uses ACF link field, it’s now time to go live. I export the database and run a query to replace any permalinks (e.g. http://example.local –> http://example.com). Perfect done! Until I look at the live site and see all link field values aren’t being returned. Ahhh!

    Problem: link field values are being stored as serialised arrays which fail to unserialise if any of the array value lengths change.

    Proposed solution: Store as html and parse to return values.

    Code: I have quickly modified the class-acf-field-link.php to do what I mean.

    <?php
    
    if( ! class_exists('acf_field_link') ) :
    
    class acf_field_link extends acf_field {
    
    	/*
    	*  __construct
    	*
    	*  This function will setup the field type data
    	*
    	*  @type	function
    	*  @date	5/03/2014
    	*  @since	5.0.0
    	*
    	*  @param	n/a
    	*  @return	n/a
    	*/
    
    	function initialize() {
    
    		// vars
    		$this->name = 'link';
    		$this->label = __("Link",'acf');
    		$this->category = 'relational';
    		$this->defaults = array(
    			'return_format'	=> 'array',
    		);
    
    	}
    
    	/*
    	*  get_link
    	*
    	*  description
    	*
    	*  @type	function
    	*  @date	16/5/17
    	*  @since	5.5.13
    	*
    	*  @param	$post_id (int)
    	*  @return	$post_id (int)
    	*/
    
    	function get_link( $value = '' ) {
    
    		// vars
    		$link = array(
    			'title'		=> '',
    			'url'		=> '',
    			'target'	=> ''
    		);
    
    		// html element (ACF N/A)
    		if ( is_string($value) && strncmp($value, '<a', 2) === 0 ) {
    			preg_match('/<a.*>(.*)<\/a>/Uims', $value, $match);
    
    			$link['title']	= isset($match[1]) ? $match[1] : '';
    			$link['url']	= $this->get_html_attribute( 'href', $value );
    			$link['target']	= $this->get_html_attribute( 'target', $value );
    
    		// array (ACF 5.6.0)
    		} elseif( is_array($value) ) {
    
    			$link = array_merge($link, $value);
    
    		// post id (ACF < 5.6.0)
    		} elseif( is_numeric($value) ) {
    
    			$link['title'] = get_the_title( $value );
    			$link['url'] = get_permalink( $value );
    
    		// string (ACF < 5.6.0)
    		} elseif( is_string($value) ) {
    
    			$link['url'] = $value;
    
    		}
    
    		// return
    		return $link;
    
    	}
    
    	/*
    	*  render_field()
    	*
    	*  Create the HTML interface for your field
    	*
    	*  @param	$field - an array holding all the field's data
    	*
    	*  @type	action
    	*  @since	3.6
    	*  @date	23/01/13
    	*/
    
    	function render_field( $field ){
    
    		// vars
    		$div = array(
    			'id'	=> $field['id'],
    			'class'	=> $field['class'] . ' acf-link',
    		);
    
    		// render scripts/styles
    		acf_enqueue_uploader();
    
    		// get link
    		$link = $this->get_link( $field['value'] );
    
    		// classes
    		if( $link['url'] ) {
    			$div['class'] .= ' -value';
    		}
    
    		if( $link['target'] === '_blank' ) {
    			$div['class'] .= ' -external';
    		}
    
    		/*<textarea id="<?php echo esc_attr($field['id']); ?>-textarea"><?php
    			echo esc_textarea('<a href="'.$link['url'].'" target="'.$link['target'].'">'.$link['title'].'</a>');
    		?></textarea>*/
    ?>
    <div <?php acf_esc_attr_e($div); ?>>
    
    	<div class="acf-hidden">
    		<a class="link-node" href="<?php echo esc_url($link['url']); ?>" target="<?php echo esc_attr($link['target']); ?>"><?php echo esc_html($link['title']); ?></a>
    		<?php foreach( $link as $k => $v ): ?>
    			<?php acf_hidden_input(array( 'class' => "input-$k", 'name' => $field['name'] . "[$k]", 'value' => $v )); ?>
    		<?php endforeach; ?>
    	</div>
    
    	<a href="#" class="button" data-name="add" target=""><?php _e('Select Link', 'acf'); ?></a>
    
    	<div class="link-wrap">
    		<span class="link-title"><?php echo esc_html($link['title']); ?></span>
    		<a class="link-url" href="<?php echo esc_url($link['url']); ?>" target="_blank"><?php echo esc_html($link['url']); ?></a>
    		<i class="acf-icon -link-ext acf-js-tooltip" title="<?php _e('Opens in a new window/tab', 'acf'); ?>"></i><?php
    		?><a class="acf-icon -pencil -clear acf-js-tooltip" data-name="edit" href="#" title="<?php _e('Edit', 'acf'); ?>"></a><?php
    		?><a class="acf-icon -cancel -clear acf-js-tooltip" data-name="remove" href="#" title="<?php _e('Remove', 'acf'); ?>"></a>
    	</div>
    
    </div>
    <?php
    
    	}
    
    	/*
    	*  render_field_settings()
    	*
    	*  Create extra options for your field. This is rendered when editing a field.
    	*  The value of $field['name'] can be used (like bellow) to save extra data to the $field
    	*
    	*  @type	action
    	*  @since	3.6
    	*  @date	23/01/13
    	*
    	*  @param	$field	- an array holding all the field's data
    	*/
    
    	function render_field_settings( $field ) {
    
    		// return_format
    		acf_render_field_setting( $field, array(
    			'label'			=> __('Return Value','acf'),
    			'instructions'	=> __('Specify the returned value on front end','acf'),
    			'type'			=> 'radio',
    			'name'			=> 'return_format',
    			'layout'		=> 'horizontal',
    			'choices'		=> array(
    				'array'			=> __("Link Array",'acf'),
    				'url'			=> __("Link URL",'acf'),
    				'element'		=> __("HTML Element",'acf'),
    			)
    		));
    
    	}
    
    	/*
    	*  format_value()
    	*
    	*  This filter is appied to the $value after it is loaded from the db and before it is returned to the template
    	*
    	*  @type	filter
    	*  @since	3.6
    	*  @date	23/01/13
    	*
    	*  @param	$value (mixed) the value which was loaded from the database
    	*  @param	$post_id (mixed) the $post_id from which the value was loaded
    	*  @param	$field (array) the field array holding all the field options
    	*
    	*  @return	$value (mixed) the modified value
    	*/
    
    	function format_value( $value, $post_id, $field ) {
    
    		// bail early if no value
    		if( empty($value) ) return $value;
    
    		// get link
    		$link = $this->get_link( $value );
    
    		// format value
    		if( $field['return_format'] == 'url' ) {
    
    			return $link['url'];
    
    		}
    
    		// HTML format value
    		if( $field['return_format'] == 'element' ) {
    
    			return $this->generate_element( $link );
    
    		}
    
    		// return link
    		return $link;
    
    	}
    
    	/*
    	*  generate_element()
    	*
    	*  Generate HTML element from link values
    	*
    	*  @type	filter
    	*  @since	N/A
    	*  @date	N/A
    	*
    	*  @param  $link (array)
    	*
    	*  @return $link (string)
    	*/
    	function generate_element( $link ) {
    		if ( empty($link) || empty($link['url']) ) return null;
    
    		return '<a href="'.$link['url'].'"'.( !empty($link['target']) ? ' target="'.$link['target'].'"' : '' ).'>'.( isset($link['title']) ? $link['title'] : '' ).'</a>';
    	}
    
    	/*
    	*  get_html_attribute()
    	*
    	*  Run regex query on html string to return attribute value
    	*
    	*  @type	filter
    	*  @since	N/A
    	*  @date	N/A
    	*
    	*  @param  $attr (string)
    	*  @param  $html (string)
    	*
    	*  @return $value (string)
    	*/
    	function get_html_attribute( $attr, $html ) {
    		$regex = '/'.$attr.'\s*=\s*[\'"]([^\'"]+)[\'"]/i';
    
    		preg_match($regex, $html, $result);
    
    		return isset($result[1]) ? $result[1] : '';
    	}
    
    	/*
    	*  validate_value()
    	*
    	*  description
    	*
    	*  @type	function
    	*  @date	11/02/2014
    	*  @since	5.0.0
    	*
    	*  @param	$post_id (int)
    	*  @return	$post_id (int)
    	*/
    
    	function validate_value( $valid, $value, $field, $input ){
    
    		// bail early if not required
    		if( !$field['required'] ) return $valid;
    
    		// URL is required
    		if( empty($value) || empty($value['url']) ) {
    
    			return false;
    
    		}
    
    		// return
    		return $valid;
    
    	}
    
    	/*
    	*  update_value()
    	*
    	*  This filter is appied to the $value before it is updated in the db
    	*
    	*  @type	filter
    	*  @since	3.6
    	*  @date	23/01/13
    	*
    	*  @param	$value - the value which will be saved in the database
    	*  @param	$post_id - the $post_id of which the value will be saved
    	*  @param	$field - the field array holding all the field options
    	*
    	*  @return	$value - the modified value
    	*/
    
    	function update_value( $value, $post_id, $field ) {
    
    		// URL is required
    		if( empty($value) || empty($value['url']) ) {
    
    			return false;
    
    		}
    
    		// Store as an html element for easier database querying
    		return $this->generate_element( $value );
    
    	}
    
    }
    
    // initialize
    acf_register_field_type( 'acf_field_link' );
    
    endif; // class_exists check
    
    ?>
    
Viewing 1 post (of 1 total)

You must be logged in to reply to this topic.

We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Cookie Policy. If you continue to use this site, you consent to our use of cookies.