5

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.

2 Answers 2

5

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);
Sign up to request clarification or add additional context in comments.

Comments

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);
}

1 Comment

Works perfectly and across complex items like tables (unlike the accepted answer)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.