It seems with version 2.6 WooCommerce have changed the way endpoints and custom profile tabs are made. More infor here https://woocommerce.wordpress.com/2016/04/21/tabbed-my-account-pages-in-2-6/ and and https://github.com/woothemes/woocommerce/wiki/2.6-Tabbed-My-Account-page
My code bellow is almost similar to the one in these links but clicking on the new profile tab keeps showing the 404 Not Found error. I tried Permalinks refresh and flush_rewrite_rules() but othing seems to work....
if ( !class_exists('My_WC_User_Company') ) {
class My_WC_User_Company {
/**
* Custom endpoint name.
*
* #var string
*/
public static $endpoint = 'my-company';
/**
* Plugin actions.
*/
public function __construct() {
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'add_endpoints' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Change the My Accout page title.
add_filter( 'the_title', array( $this, 'endpoint_title' ) );
// Insering your new tab/page into the My Account page.
add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
add_action( 'woocommerce_account_' . self::$endpoint . '_endpoint', array( $this, 'endpoint_content' ) );
}
/**
* Register new endpoint to use inside My Account page.
*
* #see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
*/
public function add_endpoints() {
add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
* Add new query var.
*
* #param array $vars
* #return array
*/
public function add_query_vars( $vars ) {
$vars[] = self::$endpoint;
return $vars;
}
/**
* Set endpoint title.
*
* #param string $title
* #return string
*/
public function endpoint_title( $title ) {
global $wp_query;
$is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
// New page title.
$title = __( 'My Company', 'domain' );
remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
}
return $title;
}
/**
* Insert the new endpoint into the My Account menu.
*
* #param array $items
* #return array
*/
public function new_menu_items( $items ) {
// Remove the logout menu item.
$logout = $items['customer-logout'];
unset( $items['customer-logout'] );
// Insert your custom endpoint.
$items[ self::$endpoint ] = __( 'My Company', 'domain' );
// Insert back the logout item.
$items['customer-logout'] = $logout;
return $items;
}
/**
* Endpoint HTML content.
*/
public function endpoint_content() {
ob_start();
// here is some content ?>
<?php
$output = ob_get_clean();
echo $output;
}
}
}
add_action('init', '_action_ssd_wp_user_company_init');
if( !( function_exists('_action_ssd_wp_user_company_init')) ){
function _action_ssd_wp_user_company_init(){
if ( get_current_user_id() && get_user_meta( get_current_user_id(), 'user_company', true ) == 'yes' ) {
new My_WC_User_Company();
}
}
}
Does anyone have any ideas what couldbe the issue?
there's something wrong with your hook... wrong timings...
these works... with 0 priority or using woocommerce_init
add_action('init', '_action_ssd_wp_user_company_init', 0 );
or
add_action('woocommerce_init', '_action_ssd_wp_user_company_init');
instead of add_action('init', '_action_ssd_wp_user_company_init');
you need to refresh permalink settings for this to work.
Related
Maybe someone could give me a hand resolving this challenge.
I was looking for a solution which would allow me to add products to cart by SKU's instead of WooCommerce generated ID's as I would like to use the same products across different CMS systems.
I have stumbled upon the below code, but it seems not to be compatible anymore? Any advice?
<?php
/**
* Plugin Name: WooCommerce: Add Product to Cart by SKU
* Plugin URI: http://remicorson.com
* Description: Just a demo!
* Version: 1.0
* Author: Remi Corson
* Author URI: http://remicorson.com/
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* WC Product Add to Cart by SKU class
*/
class WC_Add_to_Cart_by_SKU {
/**
* Constructor
*/
public function __construct() {
define( 'WC_ADD_TO_CART_BY_SKU_VERSION', '1.0' );
define( 'WC_ADD_TO_CART_BY_SKU_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
define( 'WC_ADD_TO_CART_BY_SKU_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
}
/**
* get_product_id_by_product_sku()
*
* Return product ID from product SKU
*/
public function get_product_id_by_product_sku( $add_to_cart ) {
global $wpdb;
$product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $add_to_cart ) );
if ( $product_id ) return $product_id;
return $add_to_cart;
}
}
add_filter( 'woocommerce_add_to_cart_product_id', array( new WC_Add_to_Cart_by_SKU(), 'get_product_id_by_product_sku' ) );
Source: https://gist.github.com/corsonr/c02b46bd34a8471327bbf3adee6507c8
There is no need to use a custom SQL query, as you can use the wc_get_product_id_by_sku() WooCommerce function.
Using this function is much more lighter and effective but also takes into account products that are not in trash. Something your current code doesn't do.
So, this snippet will suffice:
function filter_woocommerce_add_to_cart_product_id( $product_id ) {
// Retrieves the post type of the current post or of a given post
if ( get_post_type( $product_id ) === 'product' ) {
return $product_id;
} else {
$sku = $product_id;
}
// Get product ID by SKU
$product_id = wc_get_product_id_by_sku( $sku );
return $product_id;
}
add_filter( 'woocommerce_add_to_cart_product_id', 'filter_woocommerce_add_to_cart_product_id', 10, 1 );
Note: SKU is assumed to be a numerical value
As you can read in the note, the above answer will only work for numerical values, to make this work for all SKU values, you can use as custom query string = /?add-to-cart-sku=THE-SKU
So you get:
function action_wp_loaded( $url = false ) {
// Make sure WC is installed and add-to-cart-sku query arg exists
if ( ! class_exists( 'WC_Form_Handler' ) || ! isset( $_REQUEST['add-to-cart-sku'] ) || ! is_string( $_REQUEST['add-to-cart-sku'] ) ) {
return;
}
// Remove WooCommerce's hook, as it's useless
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
wc_nocache_headers();
$product_id = wc_get_product_id_by_sku( wp_unslash( $_REQUEST['add-to-cart-sku'] ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
return;
}
$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->get_type(), $adding_to_cart );
if ( 'variable' === $add_to_cart_handler || 'variation' === $add_to_cart_handler ) {
$was_added_to_cart = woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_variable', $product_id );
} elseif ( 'grouped' === $add_to_cart_handler ) {
$was_added_to_cart = woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_grouped', $product_id );
} elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ) {
do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url ); // Custom handler.
} else {
$was_added_to_cart = woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id );
}
// If we added the product to the cart we can now optionally do a redirect.
if ( $was_added_to_cart && 0 === wc_notice_count( 'error' ) ) {
$url = apply_filters( 'woocommerce_add_to_cart_redirect', $url, $adding_to_cart );
if ( $url ) {
wp_safe_redirect( $url );
exit;
} elseif ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
wp_safe_redirect( wc_get_cart_url() );
exit;
}
}
}
// Fire before the WC_Form_Handler::add_to_cart_action callback.
add_action( 'wp_loaded', 'action_wp_loaded', 15 );
/**
* Invoke class private method
*
* #since 0.1.0
*
* #param string $class_name
* #param string $methodName
*
* #return mixed
*/
function woo_hack_invoke_private_method( $class_name, $methodName ) {
if ( version_compare( phpversion(), '5.3', '<' ) ) {
throw new Exception( 'PHP version does not support ReflectionClass::setAccessible()' );
}
$args = func_get_args();
unset( $args[0], $args[1] );
$reflection = new ReflectionClass( $class_name );
$method = $reflection->getMethod( $methodName );
$method->setAccessible( true );
$args = array_merge( array( $reflection ), $args );
return call_user_func_array( array( $method, 'invoke' ), $args );
}
Based on: Allow adding multiple products to the cart via the add-to-cart query string & /includes/class-wc-form-handler.php
please try this one, i have include the filter call inside __constructor:
<?php
/**
* Plugin Name: WooCommerce: Add Product to Cart by SKU
* Plugin URI: http://remicorson.com
* Description: Just a demo!
* Version: 1.0
* Author: Remi Corson
* Author URI: http://remicorson.com/
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* WC Product Add to Cart by SKU class
*/
class WC_Add_to_Cart_by_SKU {
/**
* Constructor
*/
public function __construct() {
define( 'WC_ADD_TO_CART_BY_SKU_VERSION', '1.0' );
define( 'WC_ADD_TO_CART_BY_SKU_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
define( 'WC_ADD_TO_CART_BY_SKU_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
add_filter( 'woocommerce_add_to_cart_product_id', array(
$this,
'get_product_id_by_product_sku'
) );
}
/**
* get_product_id_by_product_sku()
*
* Return product ID from product SKU
*/
public function get_product_id_by_product_sku( $add_to_cart ) {
global $wpdb;
$product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $add_to_cart ) );
if ( $product_id ) {
return $product_id;
}
return $add_to_cart;
}
}
new WC_Add_to_Cart_by_SKU();
I am trying to add an include a template file located in my active child theme:
childtheme/woocommerce/myaccount/order-a-kit.php
The function use also echo "Hello World" which is displayed successfully, but not the included php template file.
I have tried those:
include($_SERVER['DOCUMENT_ROOT']."twentyseventeen-child/woocommerce/myaccount/order-a-kit.php");
include($get_stylesheet_directory_uri()."twentyseventeen-child/woocommerce/myaccount/order-a-kit.php");
include 'twentyseventeen-child/woocommerce/myaccount/order-a-kit.php';
The content of the order-a-kit.php is super simple, I am just trying to include that file:
<?php
?>
<div>
<p>
Look at me
</p>
</div>
This is my function.php section and everything is doing as it should except the include function towards the bottom:
add_filter( 'woocommerce_account_menu_items', 'add_my_menu_items', 99, 1 );
function add_my_menu_items( $items ) {
$my_items = array(
// endpoint => label
'order-a-kit' => __( 'Order A Kit', 'woocommerce'),
'orders' => __( 'Order History', 'my_plugin' ),
);
$my_items = array_slice( $items, 0, 1, true ) +
$my_items +
array_slice( $items, 1, count( $items ), true );
return $my_items;
}
//adding custom endpoint
function my_custom_endpoints() {
add_rewrite_endpoint( 'order-a-kit', EP_ROOT | EP_PAGES );
}
add_action( 'init', 'my_custom_endpoints' );
function my_custom_query_vars( $vars ) {
$vars[] = 'order-a-kit';
return $vars;
}
add_filter( 'query_vars', 'my_custom_query_vars', 0 );
function my_custom_flush_rewrite_rules() {
flush_rewrite_rules();
}
add_action( 'wp_loaded', 'my_custom_flush_rewrite_rules' );
//including custom endpoint
function my_custom_endpoint_content() {
include 'twentyseventeen-child/woocommerce/myaccount/order-a-kit.php';
echo '<p>Hello World!</p>';
}
add_action( 'woocommerce_account_order-a-kit_endpoint', 'my_custom_endpoint_content' );
?>
Any help is greatly appreciated.
As the "woocommerce" folder is inside your theme as the function.php file you just need to use:
include 'woocommerce/myaccount/order-a-kit.php';
See this related answer: WooCommerce: Adding custom template to customer account pages
Try this
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'woocommerce/myaccount/order-a-kit.php';
You can add this code to your theme's function.php:
class My_Custom_My_Account_Endpoint {
/**
* Custom endpoint name.
*
* #var string
*/
public static $endpoint = 'Your Desired Link';
/**
* Plugin actions.
*/
public function __construct() {
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'add_endpoints' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Change the My Accout page title.
add_filter( 'the_title', array( $this, 'endpoint_title' ) );
// Insering your new tab/page into the My Account page.
add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
add_action( 'woocommerce_account_' . self::$endpoint . '_endpoint', array( $this, 'endpoint_content' ) );
}
/**
* Register new endpoint to use inside My Account page.
*
* #see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
*/
public function add_endpoints() {
add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
* Add new query var.
*
* #param array $vars
* #return array
*/
public function add_query_vars( $vars ) {
$vars[] = self::$endpoint;
return $vars;
}
/**
* Set endpoint title.
*
* #param string $title
* #return string
*/
public function endpoint_title( $title ) {
global $wp_query;
$is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
// New page title.
$title = __( 'Your Item Name', 'woocommerce' );
remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
}
return $title;
}
/**
* Insert the new endpoint into the My Account menu.
*
* #param array $items
* #return array
*/
public function new_menu_items( $items ) {
// Remove the logout menu item.
$logout = $items['customer-logout'];
unset( $items['customer-logout'] );
// Insert your custom endpoint.
$items[ self::$endpoint ] = __( 'Your Item Name', 'woocommerce' );
// Insert back the logout item.
$items['customer-logout'] = $logout;
return $items;
}
/**
* Endpoint HTML content.
*/
public function endpoint_content() {
//example include('woocommerce/myaccount/Your-File.php');
include('Path-To-Your-File.php');
}
/**
* Plugin install action.
* Flush rewrite rules to make our custom endpoint available.
*/
public static function install() {
flush_rewrite_rules();
}
}
new My_Custom_My_Account_Endpoint();
// Flush rewrite rules on plugin activation.
register_activation_hook( __FILE__, array( 'My_Custom_My_Account_Endpoint', 'install' ) );
You have to simply set "Your Desired Link"x1 and "Your Item Name"x2 and "Path-To-Your-File.php"x1 in this source.
If you don't know where is your theme's function.php:
1.Log in to the WordPress Admin interface
2.In the left sidebar, hover over Appearances, then click Theme Editor
3.In the right sidebar, click functions.php
I am extending someone else's plugin. He has an action hook in the function he uses to initialize the plugin. It doesn't matter if I put echo nl2br("this is located OVER the do action anspress loaded. \n"); BELOW or ABOVE the line do_action('anspress_loaded'); - the line always get's echo'd out ABOVE another line I have being echo'd inside the other code loaded on that hook. Why is this? It's probably not TREMENDOUSLY important but I'm just curious....(noob here). Any idea?
this initializes the plugin
/**
* Initializes the plugin by setting localization, hooks, filters, and administrative functions.
*
* #return instance
*/
public static function instance() {
if ( ! isset( self::$instance ) && ! (self::$instance instanceof self) ) {
self::$instance = new self();
self::$instance->setup_constants();
self::$instance->actions = array();
self::$instance->filters = array();
add_action( 'plugins_loaded', array( self::$instance, 'load_textdomain' ) );
add_action( 'bp_loaded', array( self::$instance, 'bp_include' ) );
global $ap_classes;
$ap_classes = array();
self::$instance->includes();
self::$instance->ajax_hooks();
self::$instance->site_include();
self::$instance->anspress_forms = new AnsPress_Process_Form();
self::$instance->anspress_query_filter = new AnsPress_Query_Filter();
self::$instance->anspress_cpt = new AnsPress_PostTypes();
self::$instance->anspress_reputation = new AP_Reputation();
/*
* ACTION: anspress_loaded
* Hooks for extension to load their codes after AnsPress is leaded
*/
echo nl2br("this is located OVER the do action anspress loaded. \n");
do_action('anspress_loaded');
self::$instance->setup_hooks();
}
return self::$instance;
}
this might be important:
/**
* Register the filters and actions with WordPress.
*/
private function setup_hooks() {
foreach ( $this->filters as $hook ) {
add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->actions as $hook ) {
add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
}
I added this to my functions.php file :
add_filter ('woocommerce_add_to_cart_redirect', 'woo_redirect_to_checkout');
function woo_redirect_to_checkout() {
$checkout_url = WC()->cart->get_checkout_url();
return $checkout_url;
}
But now, all the products are re-directing strait to check-out. I would like to have this option only in one product. Is that a way I can add a product ID to that same filer?
Thank you!
You need to get the product when It is just added to cart , then check if for this product you want to redirect the cart page to checkout page . You need to change $desire_product = 'certain_product'; line on below code and It will definitely work.
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout' );
function woo_redirect_checkout() {
global $woocommerce;
$desire_product = 'certain_product';
//Get product ID
$product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $_POST['add-to-cart'] );
//Check if current product is subscription
if ( $product_id == $desire_product ){
$checkout_url = $woocommerce->cart->get_checkout_url();
return $checkout_url;
exit;
} else {
$cart_url = $woocommerce->cart->get_cart_url();
return $cart_url;
exit;
}
}
I wrote a little plugin for this, sharing it here. The plugin adds a small checkbox to the product metabox, so you can specify which products should trigger the automatic skip to checkout. Basically using the same woocommerce_add_to_cart_redirect filter as in the other answers, but providing the admin backend option to determine which products trigger the redirection.
<?php
/**
* Plugin Name: Redirect to checkout
* Plugin URI: http://stackoverflow.com/q/32962653/383847
* Description: redirect to checkout for certain products
* Version: 1.0
* Author: Kathy Darling
* Author URI: http://kathyisawesome.com
* Requires at least: 3.8
* Tested up to: 3.9
*
* Text Domain: kia-redirect-to-checkout
* Domain Path: /languages/
*
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/*
* Add text inputs to product metabox
*/
function kia_add_to_wc_metabox(){
global $post;
echo '<div class="options_group">';
// Suggested Price
echo woocommerce_wp_checkbox( array(
'id' => '_redirect_to_checkout',
'label' => __( 'Redirect to checkout', 'kia-redirect-to-checkout' ) ,
'description' => __( 'When this item is added to the cart, re-direct the customer to checkout immediately.', 'kia-redirect-to-checkout' )
)
);
echo '</div>';
}
add_action( 'woocommerce_product_options_general_product_data', 'kia_add_to_wc_metabox' );
/*
* Save extra meta info
*/
function kia_process_wc_meta_box( $post_id, $post ) {
if ( isset( $_POST['_redirect_to_checkout'] ) ) {
update_post_meta( $post_id, '_redirect_to_checkout', 'yes' );
} else {
update_post_meta( $post_id, '_redirect_to_checkout', 'no' );
}
}
add_action( 'woocommerce_process_product_meta', 'kia_process_wc_meta_box', 1, 2 );
/*
* Redirect to checkout
*/
function kia_add_to_cart_redirect( $url ){
// If product is one of our special types
if ( is_numeric( $_REQUEST['add-to-cart'] ) && kia_maybe_redirect_cart( (int) $_REQUEST['add-to-cart'] ) ) {
// Remove default cart message
WC()->clear_messages();
// Redirect to checkout
$url = WC()->cart->get_checkout_url();
}
return $url;
}
add_filter( 'woocommerce_add_to_cart_redirect', 'kia_add_to_cart_redirect' );
/*
* check if an item has custom field
*/
function kia_maybe_redirect_cart( $product_id ){
if ( 'yes' == get_post_meta( $product_id, '_redirect_to_checkout', true ) ){
return TRUE;
} else {
return false;
}
}
Updating WooCommerce 3.0+
<?php
/**
* Plugin Name: WC Redirect to checkout
* Plugin URI: http://stackoverflow.com/q/32962653/383847
* Description: Redirect to checkout for certain products
* Version: 1.0
* Author: Kathy Darling
* Author URI: http://kathyisawesome.com
* Requires at least: 3.8
* Tested up to: 3.9
* WC requires at least: 3.1.0
* WC tested up to: 4.0.1
*
* Text Domain: kia-redirect-to-checkout
* Domain Path: /languages/
*
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Add text inputs to product metabox
*/
function kia_add_to_wc_metabox(){
global $post;
echo '<div class="options_group">';
// Suggested Price
echo woocommerce_wp_checkbox( array(
'id' => '_redirect_to_checkout',
'label' => __( 'Redirect to checkout', 'kia-redirect-to-checkout' ) ,
'description' => __( 'When this item is added to the cart, re-direct the customer to checkout immediately.', 'kia-redirect-to-checkout' )
)
);
echo '</div>';
}
add_action( 'woocommerce_product_options_general_product_data', 'kia_add_to_wc_metabox' );
/**
* Save extra meta info
*
* #param WC_Product $product
*/
function kia_process_wc_meta_box( $product ) {
if ( isset( $_POST['_redirect_to_checkout'] ) ) {
$product->update_meta_data( '_redirect_to_checkout', 'yes' );
} else {
$product->update_meta_data( '_redirect_to_checkout', 'no' );
}
}
add_action( 'woocommerce_admin_process_product_object', 'kia_process_wc_meta_box' );
/**
* Redirect to checkout
*
* #param WC_Product $product
*/
function kia_add_to_cart_redirect( $url, $product ) {
// If product is one of our special products.
if ( kia_maybe_redirect_cart( $product ) ) {
// Remove default cart message.
wc_clear_notices();
// Redirect to checkout.
$url = wc_get_checkout_url();
}
return $url;
}
add_filter( 'woocommerce_add_to_cart_redirect', 'kia_add_to_cart_redirect', 10, 2 );
/**
* Check if an item has custom field.
*
* #param WC_Product $product
*/
function kia_maybe_redirect_cart( $product ) {
return wc_string_to_bool( $product instanceof WC_Product && $product->get_meta( '_redirect_to_checkout', true ) );
}
https://gist.github.com/helgatheviking/f76b97d7d19813538e32b8f5f2dae6ec
There are a few action hooks as well that you can use, for eg: woocommerce_add_to_cart which passes the product id to the callback function:
add_action( 'woocommerce_add_to_cart', 'custom_add_to_cart', 10, 2 );
function custom_add_to_cart( $cart_item_key, $product_id ) {
// replace 123 with a valid product id
if( 123 == $product_id ) {
wp_redirect( WC()->cart->get_checkout_url() );
exit;
}
}
I can already unset (remove specifics from normal posts) in the json returned from the WordPress API. I actually use the following below from this example: https://css-tricks.com/using-the-wp-api-to-fetch-posts/
What I am having trouble with and can't figure out, is how to change this so it unsets data from a Custom Post Type
Thoughts?
function qod_remove_extra_data( $data, $post, $context ) {
// We only want to modify the 'view' context, for reading posts
if ( $context !== 'view' || is_wp_error( $data ) ) {
return $data;
}
// Here, we unset any data we don't want to see on the front end:
unset( $data['author'] );
unset( $data['status'] );
unset( $data['featured_image'] );
//etc etc
return $data;
}
add_filter( 'json_prepare_post', 'qod_remove_extra_data', 12, 3 );
custom post type example filter:
function projectPost_remove_extra_data( $data, $post, $context ) {
if ( $context !== 'view' || is_wp_error( $data ) ) {
return $data;
}
// Here, we unset any data we don't want to see on the front end:
unset( $data['author'] );
return $data;
}
add_filter( 'json_prepare_project', 'projectPost_remove_extra_data', 12, 3 );
For wp-api v1.x, you need to extend WP_JSON_CustomPostType. There is an example in the pages file (class-wp-json-pages.php)
<?php
/**
* Page post type handlers
*
* #package WordPress
* #subpackage JSON API
*/
/**
* Page post type handlers
*
* This class serves as a small addition on top of the basic post handlers to
* add small functionality on top of the existing API.
*
* In addition, this class serves as a sample implementation of building on top
* of the existing APIs for custom post types.
*
* #package WordPress
* #subpackage JSON API
*/
class WP_JSON_Pages extends WP_JSON_CustomPostType {
/**
* Base route
*
* #var string
*/
protected $base = '/pages';
/**
* Post type
*
* #var string
*/
protected $type = 'page';
/**
* Register the page-related routes
*
* #param array $routes Existing routes
* #return array Modified routes
*/
public function register_routes( $routes ) {
$routes = parent::register_routes( $routes );
$routes = parent::register_revision_routes( $routes );
$routes = parent::register_comment_routes( $routes );
// Add post-by-path routes
$routes[ $this->base . '/(?P<path>.+)'] = array(
array( array( $this, 'get_post_by_path' ), WP_JSON_Server::READABLE ),
array( array( $this, 'edit_post_by_path' ), WP_JSON_Server::EDITABLE | WP_JSON_Server::ACCEPT_JSON ),
array( array( $this, 'delete_post_by_path' ), WP_JSON_Server::DELETABLE ),
);
return $routes;
}
/**
* Retrieve a page by path name
*
* #param string $path
* #param string $context
*
* #return array|WP_Error
*/
public function get_post_by_path( $path, $context = 'view' ) {
$post = get_page_by_path( $path, ARRAY_A );
if ( empty( $post ) ) {
return new WP_Error( 'json_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) );
}
return $this->get_post( $post['ID'], $context );
}
/**
* Edit a page by path name
*
* #param $path
* #param $data
* #param array $_headers
*
* #return true|WP_Error
*/
public function edit_post_by_path( $path, $data, $_headers = array() ) {
$post = get_page_by_path( $path, ARRAY_A );
if ( empty( $post ) ) {
return new WP_Error( 'json_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) );
}
return $this->edit_post( $post['ID'], $data, $_headers );
}
/**
* Delete a page by path name
*
* #param $path
* #param bool $force
*
* #return true|WP_Error
*/
public function delete_post_by_path( $path, $force = false ) {
$post = get_page_by_path( $path, ARRAY_A );
if ( empty( $post ) ) {
return new WP_Error( 'json_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) );
}
return $this->delete_post( $post['ID'], $force );
}
/**
* Prepare post data
*
* #param array $post The unprepared post data
* #param string $context The context for the prepared post. (view|view-revision|edit|embed|single-parent)
* #return array The prepared post data
*/
protected function prepare_post( $post, $context = 'view' ) {
$_post = parent::prepare_post( $post, $context );
// Override entity meta keys with the correct links
$_post['meta']['links']['self'] = json_url( $this->base . '/' . get_page_uri( $post['ID'] ) );
if ( ! empty( $post['post_parent'] ) ) {
$_post['meta']['links']['up'] = json_url( $this->base . '/' . get_page_uri( (int) $post['post_parent'] ) );
}
return apply_filters( 'json_prepare_page', $_post, $post, $context );
}
}
Replace "Pages" with "MyCustomPostTypes" and page with "mycustomposttype". Just be careful not to rename internal WordPress code that also uses the term page
Note: probably best to add this as a plugin rather than change the JSON-WP-API plugin
/**
* Plugin Name: MyCustom JSON App API
* Description: MyCustomPost handler for the JSON API
* Dependency: This plugin requires JSON-WP-API Plugin!!!!
* Author:
* Author URI:
* Version:
* Plugin URI:
*/
If possible, only the examples shown in internet is:
function qod_remove_extra_data ($ data, $ post, $ context) {
// We only want to modify the 'view' context, for reading posts
if ($ context! == 'view' || is_wp_error ($ data)) {
return $ data;
}
// Here, we unset any data we do not want to see on the front end:
unset ($data ['author']);
unset ($data ['status']);
// Continue unsetting whatever other fields you want return $ data;
}
add_filter ('json_prepare_post' 'qod remove extra_data', 12, 3);
and right is:
qod_remove_extra_data function ($ data, $ post, $ context) {
// We only want to modify the 'view' context, for reading posts
if ($ context! == 'view' || is_wp_error ($ data)) {
unset ( $data->data ['excerpt']); //Example
unset ($data->data ['content']); //Example
unset ($data->data ['name field to remove'])
//or
unset ($data->data ['name field to remove'] ['name subfield if you only want to delete the sub-field of field' ])
return $data;
}
}
add_filter ('rest_prepare_post' 'qod_remove_extra_data', 12, 3);
IMPORTANT:
Is:
add_filter ('rest_prepare_post' 'qod_remove_extra_data', 12, 3);
Not:
add_filter ('json_prepare_post' 'qod remove extra_data', 12, 3); //WRONG
If is Custom Post Type:
add_filter ('rest_prepare_{$post_type}' 'qod_remove_extra_data', 12, 3);
EXAMPLE: Name post type = product;
add_filter ('rest_prepare_product' 'qod_remove_extra_data', 12, 3);
With this code can remove the fields that you want the JSON. By using rest_prepare} _ {$ post_type decide that you eliminated every post_type fields, thus only affected the post_type you want and not all.
It should be no different to remove data from custom post types than from the built-in post types. Have you confirmed that your API call is actually returning your CPTs? First, you should look at the value of what is returned from: http://yourwebsite.com/wp-json/posts/types. Assuming that your CPT type shows up there, you should be able to query for items of that type, e.g. product, by calling: http://yourwebsite.com/wp-json/posts?type=product.
In other words, you should not change the name of the filter: you still want to tie into json_prepare_post. If you want to make your filter sensitive to post type and only remove certain fields if you have a CPT you could do something like:
function my_remove_extra_product_data( $data, $post, $context ) {
// make sure you've got the right custom post type
if ( 'product' !== $data[ 'type' ] ) {
return $data;
}
// now proceed as you saw in the other examples
if ( $context !== 'view' || is_wp_error( $data ) ) {
return $data;
}
// unset unwanted fields
unset( $data[ 'author' ] );
// finally, return the filtered data
return $data;
}
// make sure you use the SAME filter hook as for regular posts
add_filter( 'json_prepare_post', 'my_remove_extra_product_data', 12, 3 );
You can find more documentation in the WP API Getting Started Guide.