Skip to content
Advertisement

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.

Advertisement

Answer

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);
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement