Dynamic fields on crop taxonomy in farmOS 1.x

There’s probably something really obvious I’m missing here. Can anybody lend me an extra set of eyes?

farmos_crop_taxonomic_info.info

name = farmOS Crop Taxonomic Info
description = Provides additional taxonomic fields for crops in farmOS.
core = 7.x
package = farmOS Contrib
dependencies[] = ctools
dependencies[] = entity
dependencies[] = entityreference
dependencies[] = entityreference_view_widget
dependencies[] = farm_crop
dependencies[] = farm_fields_dynamic
dependencies[] = features
dependencies[] = field_group
features[features_api][] = api:2
features[field_base][] = field_farm_crop_genus
features[field_base][] = field_farm_crop_species
features[field_base][] = field_farm_crop_general_common_name
features[field_instance][] = taxonomy_term-farm_crops-field_farm_crop_genus
features[field_instance][] = taxonomy_term-farm_crops-field_farm_crop_species
features[field_instance][] = taxonomy_term-farm_crops-field_farm_crop_general_common_name

farmos_crop_taxonomic_info.module

<?php
/**
 * @file
 * farmOS Crop Taxonomic Info
 */

/**
 * Implements hook_farm_fields_dynamic_bases().
 */
function farmos_crop_taxonomic_info_farm_fields_dynamic_bases() {
  return array(
    'field_farm_crop_genus' => array(
      'active' => 1,
      'cardinality' => 1,
      'deleted' => 0,
      'entity_types' => array(),
      'field_name' => 'field_farm_crop_genus',
      'indexes' => array(
        'format' => array(
          0 => 'format',
        ),
      ),
      'locked' => 0,
      'module' => 'text',
      'settings' => array(
        'max_length' => 255,
      ),
      'translatable' => 0,
      'type' => 'text',
    ),

    'field_farm_crop_species' => array(
      'active' => 1,
      'cardinality' => 1,
      'deleted' => 0,
      'entity_types' => array(),
      'field_name' => 'field_farm_crop_species',
      'indexes' => array(
        'format' => array(
          0 => 'format',
        ),
      ),
      'locked' => 0,
      'module' => 'text',
      'settings' => array(
        'max_length' => 255,
      ),
      'translatable' => 0,
      'type' => 'text',
    ),

    'field_farm_crop_general_common_name' => array(
      'active' => 1,
      'cardinality' => 1,
      'deleted' => 0,
      'entity_types' => array(),
      'field_name' => 'field_farm_crop_general_common_name',
      'indexes' => array(
        'format' => array(
          0 => 'format',
        ),
      ),
      'locked' => 0,
      'module' => 'text',
      'settings' => array(
        'max_length' => 255,
      ),
      'translatable' => 0,
      'type' => 'text',
    ),
  );
}

/**
 * Implements hook_farm_fields_dynamic_instances().
 */
function farmos_crop_taxonomic_info_farm_fields_dynamic_instances() {
  // Start an empty array of field instance definitions.
  $field_instances = array();

  // Exported field_instance: 'farm_asset-equipment-field_farm_manufacturer'.
  $field_instances['taxonomy_term-farm_crops-field_farm_crop_genus'] = array(
    'bundle' => 'farm_crops',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => 'Taxonomic genus of this crop e.g. "Phaseolus"',
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'module' => 'text',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => 0,
      ),
    ),
    'entity_type' => 'taxonomy_term',
    'field_name' => 'field_farm_crop_genus',
    'label' => 'Genus',
    'required' => 0,
    'settings' => array(
      'text_processing' => 0,
      'user_register_form' => FALSE,
    ),
    'widget' => array(
      'active' => 1,
      'module' => 'text',
      'settings' => array(
        'size' => 60,
      ),
      'type' => 'text_textfield',
      'weight' => 1,
    ),
  );

  // Exported field_instance: 'farm_asset-equipment-field_farm_manufacturer'.
  $field_instances['taxonomy_term-farm_crops-field_farm_crop_species'] = array(
    'bundle' => 'farm_crops',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => 'Taxonomic species of this crop e.g. "vulgaris"',
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'module' => 'text',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => 0,
      ),
    ),
    'entity_type' => 'taxonomy_term',
    'field_name' => 'field_farm_crop_species',
    'label' => 'Species',
    'required' => 0,
    'settings' => array(
      'text_processing' => 0,
      'user_register_form' => FALSE,
    ),
    'widget' => array(
      'active' => 1,
      'module' => 'text',
      'settings' => array(
        'size' => 60,
      ),
      'type' => 'text_textfield',
      'weight' => 1,
    ),
  );

  // Exported field_instance: 'farm_asset-equipment-field_farm_manufacturer'.
  $field_instances['taxonomy_term-farm_crops-field_farm_crop_general_common_name'] = array(
    'bundle' => 'farm_crops',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => 'General common name of this crop e.g. "wheat", "peas", "common beans", "fava beans"',
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'module' => 'text',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => 0,
      ),
    ),
    'entity_type' => 'taxonomy_term',
    'field_name' => 'field_farm_crop_general_common_name',
    'label' => 'General Common Name',
    'required' => 0,
    'settings' => array(
      'text_processing' => 0,
      'user_register_form' => FALSE,
    ),
    'widget' => array(
      'active' => 1,
      'module' => 'text',
      'settings' => array(
        'size' => 60,
      ),
      'type' => 'text_textfield',
      'weight' => 1,
    ),
  );

  // Return the array of field instance definitions.
  return $field_instances;
}

Interestingly it shows up in the features view;

But the fields don’t show up on the crops taxonomy;

What magic incantation am I missing…?

1 Like

@Symbioquine I don’t think you need to (or necessarily should) use farm_dynamic_fields.

If all you want to do is add some fields to crop terms, then the best way to do that is:

  1. Enable the Fields UI module
  2. Go to /admin/structure/taxonomy/farm_crop_families/fields
  3. Add the fields you want (including configuring their widget and formatter settings… at this point you’ll already be able to see the fields in the form).
  4. Export the fields to your Features module. (Might be easiest to start fresh, to avoid confusing Features with any existing stuff.)

Features is intended to be used for exporting config that was created via the UI to code. It sounds like everything you want can be achieved via that standard flow.

Hope that helps!

For what it’s worth: I made farm_field_dynamic for a somewhat special case. The requirement at the time was “add this field to ALL bundles of a given entity type ONLY if the module that provides the field is enabled”.

This allowed the Equipment reference field (field_farm_equipment) to be added to all Log types (including those added by contrib modules) only when the equipment module was enabled, without it needing to know what Log types are available.

Notably, in farmOS 2.x we have a new hook for doing this, so the farm_field_dynamic module/approach is no longer necessary.

For reference:

Notably from that issue:

In farmOS 7.x-1.x (Drupal 7), I hacked together a very ugly solution that altered the Features export config to dynamically add the “Equipment used” field to all log types. This allowed all the Features to appear as “default” (not “overridden”) - but, if you tried to re-export one of the features, it would include the equipment field in the export, so you would have to avoid committing those lines of code. It was a messy workaround, and it wasn’t perfect, but it did work.

:slight_smile:

@mstenta Thanks for the tips and background on farm_field_dynamic! Switching to the normal field base/instance hooks seems to have fixed it.

The only issue left is that the fields don’t go away again if the module is disabled… not sure if there’s an easy/canonical solution to that though.

farmos_crop_taxonomic_info.info

name = farmOS Crop Taxonomic Info
description = Provides additional taxonomic fields for crops in farmOS.
core = 7.x
package = farmOS Contrib
dependencies[] = ctools
dependencies[] = farm_crop
dependencies[] = features
dependencies[] = text
features[features_api][] = api:2
features[field_base][] = field_farm_crop_genus
features[field_base][] = field_farm_crop_species
features[field_base][] = field_farm_crop_gen_common_name
features[field_instance][] = taxonomy_term-farm_crops-field_farm_crop_genus
features[field_instance][] = taxonomy_term-farm_crops-field_farm_crop_species
features[field_instance][] = taxonomy_term-farm_crops-field_farm_crop_gen_common_name

farmos_crop_taxonomic_info.module

<?php
/**
 * @file
 * farmOS Crop Taxonomic Info
 */

farmos_crop_taxonomic_info.features.field_base.inc

<?php

/**
 * @file
 * farmos_crop_taxonomic_info.features.field_base.inc
 */


/**
 * Implements hook_field_default_field_bases().
 */
function farmos_crop_taxonomic_info_field_default_field_bases() {
  $field_bases = array();

  // Exported field_base: 'field_farm_crop_genus'.
  $field_bases['field_farm_crop_genus'] = array(
    'active' => 1,
    'cardinality' => 1,
    'deleted' => 0,
    'entity_types' => array(),
    'field_name' => 'field_farm_crop_genus',
    'indexes' => array(
      'format' => array(
        0 => 'format',
      ),
    ),
    'locked' => 0,
    'module' => 'text',
    'settings' => array(
      'max_length' => 255,
    ),
    'translatable' => 0,
    'type' => 'text',
  );

  // Exported field_base: 'field_farm_crop_species'.
  $field_bases['field_farm_crop_species'] = array(
    'active' => 1,
    'cardinality' => 1,
    'deleted' => 0,
    'entity_types' => array(),
    'field_name' => 'field_farm_crop_species',
    'indexes' => array(
      'format' => array(
        0 => 'format',
      ),
    ),
    'locked' => 0,
    'module' => 'text',
    'settings' => array(
      'max_length' => 255,
    ),
    'translatable' => 0,
    'type' => 'text',
  );

  // Exported field_base: 'field_farm_crop_gen_common_name'.
  $field_bases['field_farm_crop_gen_common_name'] = array(
    'active' => 1,
    'cardinality' => 1,
    'deleted' => 0,
    'entity_types' => array(),
    'field_name' => 'field_farm_crop_gen_common_name',
    'indexes' => array(
      'format' => array(
        0 => 'format',
      ),
    ),
    'locked' => 0,
    'module' => 'text',
    'settings' => array(
      'max_length' => 255,
    ),
    'translatable' => 0,
    'type' => 'text',
  );

  return $field_bases;
}

farmos_crop_taxonomic_info.features.field_instance.inc

<?php

/**
 * @file
 * farmos_crop_taxonomic_info.features.field_instance.inc
 */

/**
 * Implements hook_field_default_field_instances().
 */
function farmos_crop_taxonomic_info_field_default_field_instances() {
  $field_instances = array();

  // Exported field_instance: 'taxonomy_term-farm_crops-field_farm_crop_genus'.
  $field_instances['taxonomy_term-farm_crops-field_farm_crop_genus'] = array(
    'bundle' => 'farm_crops',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => 'Taxonomic genus of this crop e.g. "Phaseolus"',
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'module' => 'text',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => 0,
      ),
    ),
    'entity_type' => 'taxonomy_term',
    'field_name' => 'field_farm_crop_genus',
    'label' => 'Genus',
    'required' => 0,
    'settings' => array(
      'text_processing' => 0,
      'user_register_form' => FALSE,
    ),
    'widget' => array(
      'active' => 1,
      'module' => 'text',
      'settings' => array(
        'size' => 60,
      ),
      'type' => 'text_textfield',
      'weight' => 1,
    ),
  );

  // Exported field_instance:
  // 'taxonomy_term-farm_crops-field_farm_crop_species'.
  $field_instances['taxonomy_term-farm_crops-field_farm_crop_species'] = array(
    'bundle' => 'farm_crops',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => 'Taxonomic species of this crop e.g. "vulgaris"',
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'module' => 'text',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => 0,
      ),
    ),
    'entity_type' => 'taxonomy_term',
    'field_name' => 'field_farm_crop_species',
    'label' => 'Species',
    'required' => 0,
    'settings' => array(
      'text_processing' => 0,
      'user_register_form' => FALSE,
    ),
    'widget' => array(
      'active' => 1,
      'module' => 'text',
      'settings' => array(
        'size' => 60,
      ),
      'type' => 'text_textfield',
      'weight' => 1,
    ),
  );

  // Exported field_instance:
  // 'taxonomy_term-farm_crops-field_farm_crop_gen_common_name'.
  $field_instances['taxonomy_term-farm_crops-field_farm_crop_gen_common_name'] = array(
    'bundle' => 'farm_crops',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => 'General common name of this crop e.g. "wheat", "peas", "common beans", "fava beans"',
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'module' => 'text',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => 0,
      ),
    ),
    'entity_type' => 'taxonomy_term',
    'field_name' => 'field_farm_crop_gen_common_name',
    'label' => 'General Common Name',
    'required' => 0,
    'settings' => array(
      'text_processing' => 0,
      'user_register_form' => FALSE,
    ),
    'widget' => array(
      'active' => 1,
      'module' => 'text',
      'settings' => array(
        'size' => 60,
      ),
      'type' => 'text_textfield',
      'weight' => 1,
    ),
  );

  // Translatables
  // Included for use with string extractors like potx.
  t('General Common Name');
  t('General common name of this crop e.g. "wheat", "peas", "common beans", "fava beans"');
  t('Genus');
  t('Species');
  t('Taxonomic genus of this crop e.g. "Phaseolus"');
  t('Taxonomic species of this crop e.g. "vulgaris"');

  return $field_instances;
}
1 Like

Drupal 7 has separate “enabled/disabled” and “installed/uninstalled” module states (this changes to just “installed/uninstalled” in D8+), so you may need to “uninstall” the module for Features to clean up the fields it’s managing. If that doesn’t work, then maybe Features doesn’t support that. It may also depend on whether or not data is already saved in those fields. D8+ has a much more robust system for managing all this built into core.

1 Like

My lightweight testing - drush pm-disable followed by drush pm-uninstall - didn’t seem to remove the fields either.

It’s not super important for my use-case though - mostly I’m just reporting back for completeness. :grin: Glad to hear that part might work better in 2.x.

1 Like