Answers.Body: <p><strong>Updated!</strong> based on <a href="https://civicrm.stackexchange.com/a/39253/5790">Coleman's</a> answer, and additional testing.</p>
  <p>First of all, for <code>WordReplacement</code>, if you want to update a single record it's best and most appropriate to use the <code>get</code> action to get the record ID (<code>civicrm_word_replacement.id</code>). Then (as <a href="https://civicrm.stackexchange.com/a/39253/5790">Coleman</a> noted) use the <code>create</code> action and include the <code>id</code> parameter to update just that record. (Without the <code>id</code> parameter, <code>create</code> throws an error complaining the record already exists. With it, <code>create</code> performs an update.)</p>
  <p>For the <code>replace</code> action, the <code>values</code> parameter must be an array of arrays. But, <strong>crucially</strong>, in addition to the <code>values</code> array, you <strong>must</strong> provide &quot;<em>scope</em>&quot; parameters <em>outside</em> of the <code>values</code> array.</p>
  <p>So for example, with <code>id</code> as the &quot;scope&quot; parameter, the following will update only the record matching the <code>id</code> (equivalently—but more awkwardly—than <code>create</code>):</p>
  <pre><code>$result = civicrm_api3('WordReplacement', 'replace', [
    'values' =&gt; [
      'id' =&gt; 2, // &quot;scope&quot; parameter
      [
        'find_word' =&gt; &quot;Contribute&quot;,
        'replace_word' =&gt; &quot;Give Now&quot;,
        'domain_id' =&gt; &quot;my-domain-name-here&quot;,
        'match_type' =&gt; &quot;exactMatch&quot;,
        'is_active' =&gt; 1
      ]
    ]
  ]);
  </code></pre>
  <p>The API also supports, and is in fact intended for, multiple replacements. But in this case the <code>values</code> array must contain <strong>all</strong> of the records that match the &quot;scope&quot; parameter(s). In other words, it replaces the complete set of records that match the &quot;scope&quot; parameter(s). For <code>WordReplacement</code>, if you provide only the <code>domain_id</code> as the &quot;scope&quot; parameter, the <code>replace</code> action will match all of the records for that domain, so your <code>values</code> array must contain the complete set of <code>WordReplacement</code> records for that domain. If you have 3 replacement words, this might look like the following:</p>
  <pre><code>$result = civicrm_api3('WordReplacement', 'replace', [
    'values' =&gt; [
      'domain_id' =&gt; &quot;my-domain-name-here&quot;, // &quot;scope&quot; parameter
      [
        'id' =&gt; 2,
        'find_word' =&gt; &quot;Contribute&quot;,
        'replace_word' =&gt; &quot;Give Soon&quot;,
        'match_type' =&gt; &quot;exactMatch&quot;,
        'is_active' =&gt; 1
      ],
      [
        'id' =&gt; 3,
        'find_word' =&gt; &quot;Find this&quot;,
        'replace_word' =&gt; &quot;Replace with that&quot;,
        'match_type' =&gt; &quot;exactMatch&quot;,
        'is_active' =&gt; 1
      ],
      [
        'id' =&gt; 7,
        'find_word' =&gt; &quot;Find this too&quot;,
        'replace_word' =&gt; &quot;And replace it with this&quot;,
        'match_type' =&gt; &quot;wildcardMatch&quot;,
        'is_active' =&gt; 1
      ],
    ]
  ]);
  </code></pre>
  <p>If you had four <code>WordReplacement</code> records for <em>&quot;my-domain-name-here&quot;</em>, you'll end up with only the three above after calling <code>replace</code>. The fourth record will be deleted. Conversely you can add new records by omitting the <code>id</code> parameter (provided the new records have no &quot;<em>already exists</em>&quot; conflicts).</p>
  <p>So the <code>replace</code> API action is powerful but potentially dangerous. Test carefully in a development environment before using.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-04-04T07:06:07.087Z
Answers.LastActivityDate: 2021-04-09T22:48:22.413Z
Answers.LastEditDate: 2021-04-09T22:48:22.413Z
Answers.UserDisplayName: Martin_W
Answers.Body: <p>I think there may be some misunderstanding about the purpose of the <code>replace</code> 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.</p>
  <p>Perhaps the confusion arose from similarity of <code>replace</code> and <code>WordReplacement</code>, but I do not recommend using that action with this entity, chiefly because <code>replace</code> 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!</p>
  <p>I think you are looking for the <code>create</code> action, which uses the syntax you were expecting. It will create a new <code>WordReplacement</code> record if you omit <code>id</code> from the params, or if <code>id</code> is included it will update that record.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-04-05T21:07:09.810Z
Answers.Text: 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?
Answers.UserDisplayName: Martin_W
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-04-05T21:42:48.883Z
Answers.Text: I don't recommend it because it will delete every existing `WordReplacement` record in the database! Updated my answer.
Answers.UserDisplayName: Coleman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-04-07T07:55:41.377Z
Answers.Text: Ah, finally grokked this. Expanded my answer...
Answers.UserDisplayName: Martin_W
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-04-05T01:18:03.157Z
Answers.LastActivityDate: 2021-04-05T21:42:16.543Z
Answers.LastEditDate: 2021-04-05T21:42:16.543Z
Answers.UserDisplayName: Coleman
Body: <p>I'm trying to call the <code>WordReplacement</code> API v3 with the <code>replace</code> action. The APIv3 Explorer tells me the right PHP syntax is as show below. (I previously called <code>WordReplacement</code> <code>get</code> to get the correct <code>id</code> value.)</p>
  <pre><code>$result = civicrm_api3('WordReplacement', 'replace', [
    'id' =&gt; 2,
    'find_word' =&gt; &quot;Contribute&quot;,
    'replace_word' =&gt; &quot;Give Now&quot;,
    'domain_id' =&gt; &quot;my-domain-name-here&quot;,
    'match_type' =&gt; &quot;exactMatch&quot;,
    'is_active' =&gt; 1
  ]);
  </code></pre>
  <p>But executing that in the API Explorer returns the error:</p>
  <pre><code>{
      &quot;is_error&quot;: 1,
      &quot;error_message&quot;: &quot;Mandatory key(s) missing from params array: values&quot;
  }
  </code></pre>
  <p>I figured out this is calling the &quot;generic&quot; <code>replace</code> API, and by digging through the API examples (for <code>Email</code> and <code>UFField</code>), it appears the correct syntax is something like:</p>
  <pre><code>$result = civicrm_api3('WordReplacement', 'replace', [
    'some_key' =&gt; 'some_value',
    'values' =&gt; [
      'id' =&gt; 2, // maybe this ID isn't needed here?
      'find_word' =&gt; &quot;Contribute&quot;,
      'replace_word' =&gt; &quot;Give Soon&quot;,
      'domain_id' =&gt; &quot;my-domain-name-here&quot;,
      'match_type' =&gt; &quot;exactMatch&quot;,
      'is_active' =&gt; 1
    ]
  ]);
  </code></pre>
  <p>I tried a few different guesses for <code>some_key</code> and <code>some_value</code> (and also tried omitting those entirely), but always got a new error <code>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</code>.</p>
  <p>I also looked at some of the API definition files like <code>civicrm\civicrm\api\v3\UFField.php</code>, <code>Email.php</code> and <code>WordReplacement.php</code>, as well as the API <code>getfields</code> 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.</p>
  <p>I'm running WordPress v.5.4.4 and Civi v.5.35.1.</p>
  
Tags: <api><word-replacements>
Title: What's the right syntax for the API3 "replace" action for the "WordReplacement" entity?
ThreadText: # What's the right syntax for the API3 "replace" action for the "WordReplacement" entity?
  
  (Asked by: username_0 on 2021-04-04)
  
  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.
  
  **Tags:** api, word-replacements
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_0 on 2021-04-04. Score: 2
  
  Updated! based on username_1'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 username_1 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.
  
  
  ---
  
  ### Answer by username_1 on 2021-04-05. Score: 1
  
  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.
  
  > **Comments:**
  > **username_0**: Thank you username_1. 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?  
  > **username_1**: I don't recommend it because it will delete every existing `WordReplacement` record in the database! Updated my answer.  
  > **username_0**: Ah, finally grokked this. Expanded my answer...  
  
  ---
  
  