Q:

Saving Post Data in Another Database

So my problem is:
I have a scraping script, who scrapes info and saves it into his own database, when I use that info for my posts, but what I did was copy all info and put it into wp_posts and wp_postmeta. So it creates a lot of duplicated data and basically its not very good to do that. So my question is can I somehow make that my wordpress takes data from other database, and plugins for example, Custom fields, writes his data into different database and not in postmeta table.
Thank you for answers

A:

This is possible, but you're going to have to do a lot of custom work to get what you want. If you want all of your postmeta to come from and go to a separate database, you can use these filters:

get_{$meta_type}_metadata - This filter is documented in wp-includes/meta.php. Returning a non-null value from this filter will short-circuit calls to get_metadata (used by get_post_meta).
update_{$meta_type}_metadata - This filter is also in wp-includes/meta.php. Returning a non-null value will short-circuit the update_metadata function, called by update_post_meta.
add_{$meta_type}_metadata - Effectively the same as update_{$meta_type}_metadata, except it's called for add_post_meta.
delete_{$meta_type}_metadata - Same as all of the above except used to delete metadata.

Using these four filters, you can create a custom connector to another dataset instead of using the wp_postmeta table.
<?php
class MyCustomData {
    public static $instance = null;

    private $connection = null;

    // Create a singleton instance of our class.
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public function __construct() {
        $this->init_connection();
        $this->hooks();
    }

    private function init_connection() {
        // Do whatever you need to here to create your new database connection.

        // For example, you could open a PDO connection... http://php.net/manual/en/pdo.connections.php
        $this->connection = new PDO('connection string here');
    }

    // Define your meta overrides.
    private function hooks() {
        add_filter( 'add_post_metadata', [ $this, 'add_meta' ], 10, 5 );
        update_filter( 'update_post_metadata', [ $this, 'update_meta' ], 10, 5 );
        delete_filter( 'delete_post_metadata', [ $this, 'delete_meta' ], 10, 5 );
        get_filter( 'get_post_metadata', [ $this, 'get_meta' ], 10, 5 );
    }

    /**
     * From the filter documentation in meta.php
     *
     * @param null|bool $check      Whether to allow adding metadata for the given type.
     * @param int       $object_id  Object ID.
     * @param string    $meta_key   Meta key.
     * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
     * @param bool      $unique     Whether the specified meta key should be unique
     */
    public function add_meta( $check, $object_id, $meta_key, $meta_value, $unique ) {

        // There may be cases where you _don't_ want your data going to the remote database.
        // If that happens, return null and WP will continue on it's merry way.
        if ( ! $this->allow_remote_db_action( $object_id ) ) {
            return null;
        }

        // Whatever logic you need to do here and then...
        $result = $this->connection->query('INSERT INTO ...' );

        // Returning non-null will stop WP from doing it's own thing.
        if ( $result ) {
            return $result;
        }

        // Return null to let WP go on about it's business adding post meta.
        return null;
    }

    /**
     * The other three methods are effectively the same structure: 
     * - Prepare your data
     * - Make an action against the remote database.
     * - Return null if things didn't go well and you want WP to take over, or non-null
     * if you got the result you wanted and don't need WP to do what it was doing.
     */
}

// Kick off our class and set up the filters for post meta.
add_action( 'init', 'MyCustomData::get_instance' );

I strongly advise that you properly "gate" the functions you setup, meaning that you should only be getting and sending what you need to and from the remote database, and allow WordPress to handle the rest of the postmeta. There's probably some Bad Stuff that can come out of a system like this, so be prepared for headaches and debugging sessions.

