- Help Center Home
- Getting started
- Introducing FacetWP
- Installation and your account
- FAQ
- How it works
- What are facets?
- Facet types
- Built-in facet types
- Checkboxes
- Dropdown
- Radio
- fSelect
- Hierarchy
- Slider
- Search
- Autocomplete
- Date Range
- Number Range
- Rating
- Proximity
- Map
- Pager + load more
- Sort
- Reset
- User Selections
- Add-on facet types
- Hierarchy Select
- Range List
- Time Since
- A-Z Listing
- Color
- Exclude
- Legacy facet types
- Proximity (legacy)
- Map (legacy add-on)
- Custom facet types
- Custom facet types
- Indexing
- Listing templates
- Extras & integrations
- Add-on features and extras
- Using FacetWP with …
- Built-in integrations
- Advanced Custom Fields
- WooCommerce
- SearchWP
- WP-CLI
- Add-on integrations
- Blocks
- Bricks
- Elementor
- Beaver Builder
- WP Recipe Maker and Tasty Recipes
- Relevanssi
- WPML and Polylang
- Meta Box
- Flatsome (theme)
- External integrations
- Breakdance
- Document Library Pro
- Listify (theme)
- Listable (theme)
- WPGraphQL
- Tips, tricks and known issues
- WordPress multi-site
- WP All Import
- WebToffee Import Export
- Intuitive Custom Post Order
- Custom Taxonomy Order
- Category Order and Taxonomy Terms Order
- Advanced Taxonomy Terms Order
- Post Types Order
- Easy Digital Downloads
- EDD Reviews
- WP Job Manager
- Genesis framework
- WP External Links
- ElasticPress
- Yoast SEO
- All in One SEO (Pro)
- The Events Calendar (Pro)
- Google Analytics 4
- Image Optimization by Optimole
- Meow Lightbox
- Cookiebot
- Members
- MemberPress
- Co-Authors Plus
- Weglot
- Caching, hosting & security
- Object caching
- WP Rocket
- Cloudflare
- WP Engine
- Pressable
- New Relic
- WordPress REST API Authentication
- All-In-One Security (AIOS)
- Fast Velocity Minify
- Incompatibilities
- Incompatible plugins and themes
- Troubleshooting
- Troubleshooting guide
- Using the right query
- Common issues
- Common indexing issues
- Get support
- Developers
- Hooks reference
- Indexing hooks
- Querying hooks
- Output hooks
- facetwp_facet_display_value
- facetwp_facet_html
- facetwp_facet_render_args
- facetwp_facet_pager_link
- facetwp_facet_sort_options
- facetwp_template_html
- facetwp_shortcode_html
- facetwp_render_params
- facetwp_render_output
- facetwp_builder_item_value
- facetwp_builder_dynamic_tags
- facetwp_builder_dynamic_tag_value
- Advanced hooks
- facetwp_i18n
- facetwp_scripts
- facetwp_assets
- facetwp_asset_html
- facetwp_facet_types
- facetwp_facets
- facetwp_templates
- facetwp_facet_sources
- facetwp_excluded_custom_fields
- facetwp_excluded_custom
_fields_like - facetwp_use_preloader
- facetwp_debug_hooks
- facetwp_admin_settings_capability
- upt_admin_settings_capability
- Deprecated hooks
- JavaScript reference
- Shortcodes reference
- How FacetWP works
- The FacetWP URL
- FacetWP speed and limits
- FacetWP and taxonomies
- FacetWP REST API
- Tutorials
- Code snippets library
- Feedback
- What’s new
- News and announcements
- Changelog
How to export filtered post data to a CSV


This tutorial shows how to create an “Export CSV” button that exports post data of the resulting posts before or after using facets.
The exported (and automatically downloaded) CSV file can then be used to import the data into Excel or other programs.
The code below adds all functionality needed to do this. The button will export the specified post data of all posts in the listing before or after facet filtering. It works for logged-in and logged-out users. Add the code to your (child) theme’s functions.php, a code snippets plugin, or in the Custom Hooks add-on.
The code consists of five parts:
Part 1 adds an “Export CSV” button above the listing template (the element with class facetwp-template). The button will have class fwp-export-btn, as set in line 18 (and checked in line 16). The class can be used to style the button, in lines 33-38. The button text will be “Export CSV”, as set in line 19.
Part 2 stores the (filtered) post IDs in a transient. The transient needs a $session_id, which we get with the fwp_get_export_session_id() function, which is Part 4.
For logged-in users, this $session_id is generated in line 73, with wp_get_session_token(), which gets the current session token from the logged_in cookie. For logged-out users, the $session_id is taken from a cookie fwp_export_session, which is set in Part 3.
The facetwp_filtered_post_ids hook that we use in Part 2 to get all filtered post IDs, needs a condition to make it run only on the intended listing template or page. In this example, we are using $class->ajax_params[‘template’] to check for the name of a Listing Builder listing template. So if you are using such a listing template, make sure to replace my_template in line 49 with its name. If you are using any other listing template type, you can use $class->http_params['uri'] instead, to check against the page URI (the part of the URL without the domain name and the query variables, and without beginning or ending slashes). For examples of this, see the facetwp_filtered_post_ids hook page.
Part 5 handles the export to CSV. In this example, clicking the button will export a CSV with four columns: the post ID, post title, post date, and an Advanced Custom Fields custom field (which we get with ACF’s get_field() function). You can customize what post data is exported in the CSV, by adapting lines 130-134. Each of these columns in the CSV needs a heading, which can be set in lines 122-125.
If the export button should be available only for logged-in users, you could use an if ( is_user_logged_in() ) condition within the facetwp_scripts hook, surrounding all code within it. In that case you can remove Part 3 entirely, and also the cookie fallback in lines 77-81, and the wp_ajax_nopriv_fwp_export_csv action hook in line 86.
How to use custom PHP code?
PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info
<?php // Export filtered post data to a CSV // Part 1 - Add the "Export CSV" button above the listing template add_action( 'facetwp_scripts', function() { ?> <script> var fwp_export = { nonce: '<?php echo wp_create_nonce( 'fwp_export_csv' ); ?>', ajaxurl: '<?php echo admin_url( 'admin-ajax.php' ); ?>' }; </script> <script> (function() { document.addEventListener('facetwp-loaded', function() { // Only inject the button once if (!document.querySelector('.fwp-export-btn')) { var btn = document.createElement('button'); btn.className = 'fwp-export-btn'; btn.textContent = 'Export CSV'; document.querySelector('.facetwp-template').insertAdjacentElement('beforebegin', btn); btn.addEventListener('click', function() { var params = new URLSearchParams(); params.set('action', 'fwp_export_csv'); params.set('nonce', fwp_export.nonce); window.location.href = fwp_export.ajaxurl + '?' + params.toString(); }); } }); })(); </script> <style> /* Style your Export CSV button */ .fwp-export-btn { margin: 20px 0; } </style> <?php }, 100 ); // Part 2 - Store the filtered post IDs in a transient add_filter( 'facetwp_filtered_post_ids', function( $post_ids, $class ) { // Only store the transient on the relevant listing. // Use $class->ajax_params['template'] to check for a FacetWP Listing Builder listing template. // Or use $class->http_params['uri'] to check the URI if it is another listing template type // For examples, see: https://facetwp.com/help-center/developers/hooks/querying-hooks/facetwp_filtered_post_ids/#usage-examples if ( 'my_template' !== $class->ajax_params['template'] ) { // Change "my_template" to the name of your Listing Builder listing template return $post_ids; } $session_id = fwp_get_export_session_id(); if ( empty( $session_id ) ) { return $post_ids; } set_transient( 'fwp_export_ids_' . $session_id, $post_ids, 5 * MINUTE_IN_SECONDS ); return $post_ids; }, 10, 2 ); // Part 3 - Set cookie instead of session ID for logged-out users // Remove this part if the button is admin-only add_action( 'init', function() { if ( ! is_user_logged_in() && empty( $_COOKIE['fwp_export_session'] ) ) { $token = wp_generate_password( 12, false ); setcookie( 'fwp_export_session', $token, time() + 3600, COOKIEPATH, COOKIE_DOMAIN ); $_COOKIE['fwp_export_session'] = $token; // Make it available in the same request } } ); // Part 4 - Get the session ID from the transient (when logged in) or cookie (when logged out) function fwp_get_export_session_id() { $token = wp_get_session_token(); if ( ! empty( $token ) ) { return $token; } // Cookie fallback for logged-out users // Remove these lines if the button is admin-only return ! empty( $_COOKIE['fwp_export_session'] ) ? sanitize_key( $_COOKIE['fwp_export_session'] ) : ''; } // Part 5 - Handle CSV export add_action( 'wp_ajax_fwp_export_csv', 'fwp_handle_export_csv' ); add_action( 'wp_ajax_nopriv_fwp_export_csv', 'fwp_handle_export_csv' ); // Only for logged-out users. Remove if the button is admin-only. function fwp_handle_export_csv() { ob_start(); // Catch any accidental output check_ajax_referer( 'fwp_export_csv', 'nonce' ); $session_id = fwp_get_export_session_id(); if ( empty( $session_id ) ) { wp_die( 'Session not found.' ); } $post_ids = get_transient( 'fwp_export_ids_' . $session_id ); if ( empty( $post_ids ) ) { wp_die( 'No results to export.' ); } $query = new WP_Query( [ 'post__in' => $post_ids, 'orderby' => 'post__in', 'posts_per_page' => - 1, 'post_type' => 'any', ] ); ob_end_clean(); // Discard any buffered output before sending headers header( 'Content-Type: text/csv; charset=utf-8' ); header( 'Content-Disposition: attachment; filename="export.csv"' ); $out = fopen( 'php://output', 'w' ); if ( ! $out ) { wp_die( 'Could not open output stream.' ); } // Add CSV column headings for each post data output below fputcsv( $out, [ 'Post ID', 'Post Title', 'Post Date', 'My field' ] ); foreach ( $query->posts as $post ) { fputcsv( $out, [ $post->ID, $post->post_title, $post->post_date, get_field( 'my_custom_field', $post->ID ), // example ACF field //.. add any other data you want to export ] ); } fclose( $out ); exit; }
See also
- The facetwp_scripts hook
- The facetwp-loaded event
- The facetwp_filtered_post_ids hook
- Using the Listing Builder
- Listing templates
- Using FacetWP with Advanced Custom Fields
Last updated: May 6, 2026