setup_hooks(); } /** * Set up hooks for various purposes. * * This method adds hooks for different purposes as needed. * * @since 1.0.0 * * @return void */ protected function setup_hooks(): void { /** * Fires at the beginning of an export, before any headers are sent. */ add_action( 'export_wp', array( $this, 'export' ) ); } /** * Sets up the necessary hooks for the export process. * * @since 1.0.0 * * @return void */ public function export(): void { add_action( 'the_post', array( $this, 'prepare' ) ); add_filter( 'wxr_export_skip_postmeta', array( $this, 'extend' ), 10, 3 ); } /** * Saves a temporary marker as postmeta, * which allows to hook into the export process per post later on. * * Called via setup_postdata() at the beginning of each singular post export. * * Fires once the post data has been set up. * * @since 1.0.0 * * @param WP_Post $post The Post object (passed by reference). * @return void */ public function prepare( WP_Post $post ): void { if ( Validate::event_post_id( $post->ID ) ) { add_post_meta( $post->ID, self::POST_META, true ); } } /** * Extend WordPress' native Export * * WordPress' native Export can be extended in hacky way using `wxr_export_skip_postmeta` * where GatherPress echos out some pseudo-post-meta fields, * before returning `false` like the default. * * @source https://github.com/WordPress/wordpress-develop/blob/6.5/src/wp-admin/includes/export.php#L655-L677 * * Normally this filters whether to selectively skip post meta used for WXR exports. * Returning a truthy value from the filter will skip the current meta object from being exported. * * @see https://developer.wordpress.org/reference/hooks/wxr_export_skip_postmeta/ * * But because there is no 'do_action('per-exported-post)', * GatherPress created a post_meta entry as a temporary marker, to be used as an entry-point into * WordPress' native export process, which is used now. * * @since 1.0.0 * * @param bool $skip Whether to skip the current post meta. Default false. * @param string $meta_key Current meta key. * @param object $meta Current meta object. * @return bool Whether to skip the current post meta. Default false. */ public function extend( bool $skip, string $meta_key, object $meta ): bool { if ( self::POST_META === $meta_key ) { // Echos out xml with pseudo-postmeta. $this->run( get_post( $meta->post_id ) ); // Deletes temporary marker. delete_post_meta( $meta->post_id, self::POST_META ); // Prevent 'normal' export processing for that particular postmeta field, // because it doesn't exist in real and will trigger an error. return true; } return $skip; } /** * Exports all custom data. * * Gets all 'pseudopostmetas' and generates WXR-compatible output for each, * the generated xml markup is rendered into the WordPress export file directly. * * An export file like this can be imported into GatherPress using * the native 'WordPress importer' and its potential replacement the 'WordPress importer (v2)'. * * @since 1.0.0 * * @param WP_Post $post Current 'gatherpress_event' post being exported. * @return void */ public function run( WP_Post $post ): void { $pseudopostmetas = $this->get_pseudopostmetas(); array_walk( $pseudopostmetas, array( $this, 'render' ), $post ); } /** * Render custom post_meta data into xml markup to be used while WordÜress' native export. * * @param array $callbacks Associative array with (import & export) callback functions for * the non-existent post_meta entry, named by $key. * @param string $key Name of the custom post_meta, that should be exported. * @param WP_Post $post The currently exported 'gatherpress_event' post. * * @return void * @since 1.0.0 */ public function render( array $callbacks, string $key, WP_Post $post ) { if ( ! isset( $callbacks['export_callback'] ) || ! is_callable( $callbacks['export_callback'] ) || ! function_exists( 'wxr_cdata' ) ) { return; } $value = call_user_func( $callbacks['export_callback'], $post ); // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- wxr_cdata handles escaping. ?> ID ); return maybe_serialize( $event->get_datetime() ); } }