1

I'm trying to call the WordReplacement API v3 with the replace action. The APIv3 Explorer tells me the right PHP syntax is as show below. (I previously called WordReplacement get to get the correct id value.)

$result = civicrm_api3('WordReplacement', 'replace', [
  'id' => 2,
  'find_word' => "Contribute",
  'replace_word' => "Give Now",
  'domain_id' => "my-domain-name-here",
  'match_type' => "exactMatch",
  'is_active' => 1
]);

But executing that in the API Explorer returns the error:

{
    "is_error": 1,
    "error_message": "Mandatory key(s) missing from params array: values"
}

I figured out this is calling the "generic" replace API, and by digging through the API examples (for Email and UFField), it appears the correct syntax is something like:

$result = civicrm_api3('WordReplacement', 'replace', [
  'some_key' => 'some_value',
  'values' => [
    'id' => 2, // maybe this ID isn't needed here?
    'find_word' => "Contribute",
    'replace_word' => "Give Soon",
    'domain_id' => "my-domain-name-here",
    'match_type' => "exactMatch",
    'is_active' => 1
  ]
]);

I tried a few different guesses for some_key and some_value (and also tried omitting those entirely), but always got a new error Type error: Argument 3 passed to civicrm_api() must be of the type array, null given, called in /longpathgoeshere/wordpress/wp-content/plugins/civicrm/civicrm/api/v3/utils.php on line 1813.

I also looked at some of the API definition files like civicrm\civicrm\api\v3\UFField.php, Email.php and WordReplacement.php, as well as the API getfields output, but nothing helped me to infer what the correct syntax should be. So I'd also be interested in hints on how to understand and learn from those as a developer.

I'm running WordPress v.5.4.4 and Civi v.5.35.1.

1

Updated! based on Coleman's answer, and additional testing.

First of all, for WordReplacement, if you want to update a single record it's best and most appropriate to use the get action to get the record ID (civicrm_word_replacement.id). Then (as Coleman noted) use the create action and include the id parameter to update just that record. (Without the id parameter, create throws an error complaining the record already exists. With it, create performs an update.)

For the replace action, the values parameter must be an array of arrays. But, crucially, in addition to the values array, you must provide "scope" parameters outside of the values array.

So for example, with id as the "scope" parameter, the following will update only the record matching the id (equivalently—but more awkwardly—than create):

$result = civicrm_api3('WordReplacement', 'replace', [
  'values' => [
    'id' => 2, // "scope" parameter
    [
      'find_word' => "Contribute",
      'replace_word' => "Give Now",
      'domain_id' => "my-domain-name-here",
      'match_type' => "exactMatch",
      'is_active' => 1
    ]
  ]
]);

The API also supports, and is in fact intended for, multiple replacements. But in this case the values array must contain all of the records that match the "scope" parameter(s). In other words, it replaces the complete set of records that match the "scope" parameter(s). For WordReplacement, if you provide only the domain_id as the "scope" parameter, the replace action will match all of the records for that domain, so your values array must contain the complete set of WordReplacement records for that domain. If you have 3 replacement words, this might look like the following:

$result = civicrm_api3('WordReplacement', 'replace', [
  'values' => [
    'domain_id' => "my-domain-name-here", // "scope" parameter
    [
      'id' => 2,
      'find_word' => "Contribute",
      'replace_word' => "Give Soon",
      'match_type' => "exactMatch",
      'is_active' => 1
    ],
    [
      'id' => 3,
      'find_word' => "Find this",
      'replace_word' => "Replace with that",
      'match_type' => "exactMatch",
      'is_active' => 1
    ],
    [
      'id' => 7,
      'find_word' => "Find this too",
      'replace_word' => "And replace it with this",
      'match_type' => "wildcardMatch",
      'is_active' => 1
    ],
  ]
]);

If you had four WordReplacement records for "my-domain-name-here", you'll end up with only the three above after calling replace. The fourth record will be deleted. Conversely you can add new records by omitting the id parameter (provided the new records have no "already exists" conflicts).

So the replace API action is powerful but potentially dangerous. Test carefully in a development environment before using.

0

I think there may be some misunderstanding about the purpose of the replace action. To clarify, this is a specialized api action intended to perform a simultaneous create/update/delete on a bunch of records. It's typical use would be to replace all of a contact's email addresses with a new set of email addresses.

Perhaps the confusion arose from similarity of replace and WordReplacement, but I do not recommend using that action with this entity, chiefly because replace is supposed to operate within some bounds (e.g. replace emails just for this one contact). Without those bounds it will delete every existing record in the database. Danger!

I think you are looking for the create action, which uses the syntax you were expecting. It will create a new WordReplacement record if you omit id from the params, or if id is included it will update that record.

3
  • Thank you Coleman. I wasn't confused about "WordReplacement" vs. "replace" though. I had existing WordReplacement records that I wanted to update, so "replace" seemed to be the way to do that. I saw that calling the "create" action for an existing WordReplacement record threw an error, but did not think to include the existing ID. So rather than go through "get", "delete" and "create", I tried to figure out "replace". -- So, while, "create" with the existing ID is preferred, are there known issues or other reasons why "replace" won't work reliably with the "WordReplacement" entity? – Martin_W Apr 5 at 21:07
  • I don't recommend it because it will delete every existing WordReplacement record in the database! Updated my answer. – Coleman Apr 5 at 21:42
  • Ah, finally grokked this. Expanded my answer... – Martin_W Apr 7 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.