public static function handle_manipulation($manipulation)
    {
        if (!static::config()->get('enabled')) {
            return;
        }

        // First, extract any state that is in the manipulation itself
        foreach ($manipulation as $table => $details) {
            if (!isset($manipulation[$table]['class'])) {
                $manipulation[$table]['class'] = DataObject::getSchema()->tableClass($table);
            }
            $manipulation[$table]['state'] = array();
        }

        SearchVariant::call('extractManipulationState', $manipulation);

        // Then combine the manipulation back into object field sets

        $writes = array();

        foreach ($manipulation as $table => $details) {
            if (!isset($details['id'])) {
                continue;
            }

            $id = $details['id'];
            $state = $details['state'];
            $class = $details['class'];
            $command = $details['command'];
            $fields = isset($details['fields']) ? $details['fields'] : array();

            $base = DataObject::getSchema()->baseDataClass($class);
            $key = "$id:$base:" . serialize($state);

            $statefulids = array(array('id' => $id, 'state' => $state));

            // Is this the first table for this particular object? Then add an item to $writes
            if (!isset($writes[$key])) {
                $writes[$key] = array(
                    'base' => $base,
                    'class' => $class,
                    'id' => $id,
                    'statefulids' => $statefulids,
                    'command' => $command,
                    'fields' => array()
                );
            } elseif (is_subclass_of($class, $writes[$key]['class'])) {
                // Otherwise update the class label if it's more specific than the currently recorded one
                $writes[$key]['class'] = $class;
            }

            // Update the fields
            foreach ($fields as $field => $value) {
                $writes[$key]['fields']["$class:$field"] = $value;
            }
        }

        // Trim non-delete records without fields
        foreach (array_keys($writes) as $key) {
            if ($writes[$key]['command'] !== 'delete' && empty($writes[$key]['fields'])) {
                unset($writes[$key]);
            }
        }

        // Then extract any state that is needed for the writes

        SearchVariant::call('extractManipulationWriteState', $writes);

        // Submit all of these writes to the search processor

        static::process_writes($writes);
    }