Extend the functionality of the Custom Field column

Admin Columns Pro comes with great support for Custom Fields. It allows you to sort, filter, export, and search on custom field values. It even allows you to change the value of custom fields right from the overview page with our inline edit features. To make it even more awesome, we introduced some integrations for the most populate custom field plugins like Advanced Custom Fields, Pods, Type and Meta Box.

But if you’re working with your own custom field logic or just working with unsupported third-party columns, you might run into some limitation in our custom field column. In this article, I will explain how you can extend the Custom Field column with hooks to make it more compatible with your own or third-party custom logic.

Tip Did you know it is often possible to replace unsupported third-party columns with our Custom Field column?

Limitations with the Custom Field column

The custom field column is a one-fits-all solution to display custom fields on your overview pages, but it has some limitations. Although the custom field column has quite some settings to set up the column, it does and cannot know everything about the context of your custom fields. Let’s take the following example:

You have a custom theme where you have defined your own custom fields and logic on how to edit and display them on your website. One of the custom fields is called ‘my_color_field’ and contains data that is populated by a list of key => values that are defined in your codebase. The actual value stored in the database is the key which represents a hexadecimal color value.

// Function to get the available options as key => value
function get_brand_colors() {
	return [
		'#000000' => 'Solid Black',
		'#FFCC00' => 'Primary Orange',
		'#FF0000' => 'Secondary Red',
		'#0058AB' => 'Ocean Blue',
	];
}

// Function to easily display the label of the color
function get_brand_color_label( $post_id ) {
	$colors = get_brand_colors();

	// Get the color value from the custom field
	$value = get_post_meta( $post_id, 'my_color_field', true );

	if ( ! isset( $colors[ $value ] ) ) {
		return false;
	}

	return $colors[ $value ];
}

// Data is stored like this
update_post_meta( $post_id, 'my_color_field', '#000000' );

// Data in template is retrieved like this
echo get_brand_color_label( $post_id );

With the custom field column, it is possible to create a column for this field but it will show the raw value instead of the label that is showed with the get_brand_color_value method. When using our editing feature for this column you will also get a text input field instead of a drop-down list since our plugin does not know about the existence of the available API methods.

Starting situation

Based on the use case above, you can start by creating a custom field column for your custom field. Given that we like to extend the column with our own logic, we leave the Field type to ‘Default’. You can also enable editing and filtering since we’re going to change all of that in the steps below.

Altering the display value

We now have a working column that shows the raw value of the custom field. Instead of the key, we want to show the label to make something meaningful of the column. To do that we can use the ‘ac/column/value’ hook to alter the value of the column.

add_filter( 'ac/column/value', function ( $value, $id, AC\Column $column ) {

	// First check the custom field column and for a specific custom field key
	if ( $column instanceof ACP\Column\CustomField && 'my_color_field' === $column->get_meta_key() ) {

		// Now we use the color label for displaying instead of the color code
		$label = get_brand_color_label( $id );

		// As an extra we wrap the value in a colored block
		$value = sprintf(
			'<span style="background-color: %s;">%s</span>',
			$value,
			$label
		);
	}

	return $value;
}, 10, 3 );

Because this hook runs for all column values, we need to make sure that we alter the value of the correct column. To do that, we check for a CustomField column instance and check for the right custom field key. Once we know that we have the correct column at our disposal, we can run the API method from the theme to get the formatted value for a specific $id.

As an extra step, we add a small colored box after the title to make it easier to understand what actual color the label is representing. For this, we use the raw_value() since that can already be used to use as a CSS background color.

Altering the export value

The hook we used above will change the display value of the column on the overview page. Unfortunately, this hook does not automatically change the export value of your column. We do have a different hook for that but an important thing to keep in mind is that it uses the same arguments, but not in the same order as the display value hook. So to change the export value to the label instead of the hexadecimal value, we can the following code.

add_filter( 'ac/export/value', function( $value, AC\Column $column, $id ) {
	if ( $column instanceof ACP\Column\CustomField && 'my_color_field' === $column->get_meta_key() ) {
		$value = get_brand_color_label( $id );
	}

	return $value;
}, 10, 3 );

The extra color block that we’ve added in the display value is not needed for the export value, so a simple call to our API method is sufficient in this case. A fallback to a dash value (the value we use for displaying empty values on the overview) can also be omitted.

Extend the editing functionality

Enabling Inline Editing for this column will give you a text field for editing instead of a drop-down that contains the key-value options from our API method. In order to change the text input to a drop-down list with our values, we can use the following hook.

add_filter( 'acp/editing/view_settings', function( $data, AC\Column $column ) {
   if ( $column instanceof ACP\Column\CustomField && 'my_color_field' === $column->get_meta_key() ) {
      $data['type'] = 'select';
      $data['options'] = get_brand_colors();
   }

   return $data;
}, 10, 2 );

Again we check if the column argument is our column that we want to alter. The next step is to change the editable type to a drop-down box by setting it to ’select’. After that, we can provide an array for the ‘options’ argument. The API method my_brand_color_values() returns exactly what we need. The result of our inline edit (and also bulk edit) hook will be like this.

Extend the filter functionality

Admin Column Pro has two ways of filtering the data on the overview page. There is a filter feature that adds drop-downs to the overview page, and there is our Smart Filtering feature that allows you to add new filters to the overview page dynamically. At this moment we do have a filter to alter the options that are available in the filter drop-down.

By default the drop-down list will show you the available meta keys, but also here the options are just a representation of a key-value pair. That means we can use the my_brand_color_values function again to set the available list options for our filter drop-down with the corresponding labels.

add_filter( 'acp/filtering/dropdown_args', function( $args, AC\Column $column ){
	if ( $column instanceof ACP\Column\CustomField && 'my_color_field' === $column->get_meta_key() ) {
		$args['options'] = get_brand_colors();
	}

	return $args;
}, 10, 2 );

Give it some extra love

Since we’re using multiple hooks to change a single column, I prefer to put all logic into a single class. Let’s create a class and try to abstract some of the methods to share some logic.
class AcpCustomFieldColorColumn {

	const META_KEY = 'my_color_field';

	public function __construct() {
		add_filter( 'ac/column/value', [ $this, 'display_value' ], 10, 3 );
		add_filter( 'ac/export/value', [ $this, 'export_value' ], 10, 3 );
		add_filter( 'acp/editing/view_settings', [ $this, 'edit_settings' ], 10, 2 );
		add_filter( 'acp/filtering/dropdown_args', [ $this, 'filter_settings' ], 10, 2 );
	}

	private function is_targeted_column( AC\Column $column ) {
		return $column instanceof ACP\Column\CustomField && self::META_KEY === $column->get_meta_key();
	}

	public function display_value( $value, $id, AC\Column $column ) {
		if ( $this->is_targeted_column( $column ) ) {

			// The method `get_raw_value( $id )` fetches the value using `get_post_meta()`
			$color = $column->get_raw_value( $id );

			$label = get_brand_color_label( $id );

			$value = sprintf(
				'<span style="background-color: %s;">%s</span>',
				$color,
				$label
			);
		}

		return $value;
	}

	public function export_value( $value, AC\Column $column, $id ) {
		return $this->is_targeted_column( $column ) 
			? get_brand_color_label( $id ) 
			: $value;
	}

	public function edit_settings( $data, AC\Column $column ) {
		if ( $this->is_targeted_column( $column ) ) {
			$data['type'] = 'select';
			$data['options'] = get_brand_colors();
		}

		return $data;
	}

	public function filter_settings( $args, AC\Column $column ){
		if( $this->is_targeted_column( $column ) ){
			$args['options'] = get_brand_colors();
		}

		return $args;
	}

}

new AcpCustomFieldColorColumn();

Wrapping Up

Using hooks to alter the behavior of the custom field column is a fast and easy way to make changes to this column. But if you have quite some logic and want an even more sustainable solution, you could choose to write your own column by using our toolkit.