'How to MODIFY a Google Docs document via API using search-and-replace?

I need an example of how to modify an existing document with existing text in Google Docs via API. The documentation only shows how to insert and delete text, but not how to update. Have been looking frantically on the web to find examples or a direction on how to do it but without luck.



Solution 1:[1]

Finally figured it out myself.

First, follow this video to prepare authentication to the Google Docs API (even though it's about Google Sheets but the process is basically the same). Basically it consists of these steps:

  • create project in Google Developer Console
  • enable Google Docs API
  • create credentials, including a service account for programmatic access
  • share your document with the service account client email address
  • install Google API's PHP client: composer require google/apiclient

Then create a script like the following:

require_once(__DIR__ .'/vendor/autoload.php');
$client = new \Google_Client();
$client->setApplicationName('Some name');  //this name doesn't matter
$client->setScopes([\Google_Service_Docs::DOCUMENTS]);
$client->setAccessType('offline');
$client->setAuthConfig(__DIR__ .'/googleapi-credentials.json');  //see https://www.youtube.com/watch?v=iTZyuszEkxI for how to create this file
$service = new \Google_Service_Docs($client);

$documentId = 'YOUR-DOCUMENT-ID-GOES-HERE';  //set your document ID here, eg. "j4i1m57GDYthXKqlGce9WKs4tpiFvzl1FXKmNRsTAAlH"
$doc = $service->documents->get($documentId);

// Collect all pieces of text (see https://developers.google.com/docs/api/concepts/structure to understand the structure)
$allText = [];
foreach ($doc->body->content as $structuralElement) {
    if ($structuralElement->paragraph) {
        foreach ($structuralElement->paragraph->elements as $paragraphElement) {
            if ($paragraphElement->textRun) {
                $allText[] = $paragraphElement->textRun->content;
            }
        }
    }
}

// Go through and create search/replace requests
$requests = $textsAlreadyDone = $forEasyCompare = [];
foreach ($allText as $currText) {
    if (in_array($currText, $textsAlreadyDone, true)) {
        // If two identical pieces of text are found only search-and-replace it once - no reason to do it multiple times
        continue;
    }

    if (preg_match_all("/(.*?)(dogs)(.*?)/", $currText, $matches, PREG_SET_ORDER)) {
        //NOTE: for simple static text searching you could of course just use strpos()
        // - and then loop on $matches wouldn't be necessary, and str_replace() would be simplified
        $modifiedText = $currText;
        foreach ($matches as $match) {
            $modifiedText = str_replace($match[0], $match[1] .'cats'. $match[3], $modifiedText);
        }

        $forEasyCompare[] = ['old' => $currText, 'new' => $modifiedText];

        $replaceAllTextRequest = [
            'replaceAllText' => [
                'replaceText' => $modifiedText,
                'containsText' => [
                    'text' => $currText,
                    'matchCase' => true,
                ],
            ],
        ];

        $requests[] = new \Google_Service_Docs_Request($replaceAllTextRequest);
    }
    $textsAlreadyDone[] = $currText;
}

// you could dump out $forEasyCompare to see the changes that would be made

$batchUpdateRequest = new \Google_Service_Docs_BatchUpdateDocumentRequest(['requests' => $requests]);
$response = $service->documents->batchUpdate($documentId, $batchUpdateRequest);

Solution 2:[2]

This is my way - easy one

public function replaceText($search, $replace)
{
    $client = $this->getClient();
    $service = new \Google_Service_Docs($client);
    $documentId = ''; // Put your document ID here


    $e = new \Google_Service_Docs_SubstringMatchCriteria();
    $e->text = "{{".$search."}}";
    $e->setMatchCase(false);


    $requests[] = new \Google_Service_Docs_Request(array(
        'replaceAllText' => array(
            'replaceText' => $replace,
            'containsText' => $e
        ),
    ));

    $batchUpdateRequest = new \Google_Service_Docs_BatchUpdateDocumentRequest(array(
        'requests' => $requests
    ));

    $response = $service->documents->batchUpdate($documentId, $batchUpdateRequest);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Sarke