Skip to content

Instantly share code, notes, and snippets.

@FrEaKmAn
Last active April 7, 2021 08:21
Show Gist options
  • Save FrEaKmAn/70666db78b0cdf3ce5776a0f1aaf79b3 to your computer and use it in GitHub Desktop.
Save FrEaKmAn/70666db78b0cdf3ce5776a0f1aaf79b3 to your computer and use it in GitHub Desktop.
<?php
class WCML_REST_API_Support{
/** @var woocommerce_wpml */
private $woocommerce_wpml;
/** @var Sitepress */
private $sitepress;
/** @var WCML_REST_API_Query_Filters_Products */
private $query_filters_products;
/** @var WCML_REST_API_Query_Filters_Orders */
private $query_filters_orders;
/** @var WCML_REST_API_Query_Filters_Terms */
private $query_filters_terms;
/** @var WPML_Admin_Post_Actions */
private $wpml_post_translations;
/**
* WCML_REST_API_Support constructor.
*
* @param woocommerce_wpml $woocommerce_wpml
* @param SitePress $sitepress
* @param WCML_REST_API_Query_Filters_Products $query_filters_products
* @param WCML_REST_API_Query_Filters_Orders $query_filters_orders
* @param WCML_REST_API_Query_Filters_Terms $query_filters_terms
* @param WPML_Post_Translation $wpml_post_translations
*/
public function __construct(
woocommerce_wpml $woocommerce_wpml,
SitePress $sitepress,
WCML_REST_API_Query_Filters_Products $query_filters_products,
WCML_REST_API_Query_Filters_Orders $query_filters_orders,
WCML_REST_API_Query_Filters_Terms $query_filters_terms,
WPML_Post_Translation $wpml_post_translations
) {
$this->woocommerce_wpml = $woocommerce_wpml;
$this->sitepress = $sitepress;
$this->query_filters_products = $query_filters_products;
$this->query_filters_orders = $query_filters_orders;
$this->query_filters_terms = $query_filters_terms;
$this->wpml_post_translations = $wpml_post_translations;
$this->prevent_default_lang_url_redirect();
}
public function add_hooks(){
add_action( 'rest_api_init', array( $this, 'set_language_for_request' ) );
add_action( 'parse_query', array($this, 'auto_adjust_included_ids') );
// Products
add_action( 'woocommerce_rest_prepare_product_object', array( $this, 'append_product_language_and_translations' ) );
add_action( 'woocommerce_rest_prepare_product_object', array( $this, 'append_product_secondary_prices' ) );
add_action( 'woocommerce_rest_insert_product_object', array( $this, 'set_product_language' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product_object', array( $this, 'set_product_custom_prices' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product_object', array( $this, 'set_product_images' ), 10, 2 );
add_action( 'woocommerce_rest_prepare_product_cat', array( $this, 'append_category_language_and_translations' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product_cat', array( $this, 'set_category_language' ), 10, 2 );
add_action( 'woocommerce_rest_update_product_cat', array( $this, 'set_category_language' ), 10, 2 );
add_action( 'woocommerce_rest_prepare_product_tag', array( $this, 'append_tag_language_and_translations' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product_tag', array( $this, 'set_tag_language' ), 10, 2 );
add_action( 'woocommerce_rest_update_product_tag', array( $this, 'set_tag_language' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product_object', array( $this, 'copy_custom_fields_from_original' ), 10, 1 );
add_action( 'woocommerce_rest_prepare_product_object', array( $this, 'copy_product_custom_fields' ), 10 , 3 );
// Orders
add_action( 'woocommerce_rest_insert_shop_order_object' , array( $this, 'set_order_language' ), 10, 2 );
$this->add_hooks_specific_for_v1();
$this->query_filters_products->add_hooks();
$this->query_filters_orders->add_hooks();
$this->query_filters_terms->add_hooks();
}
private function add_hooks_specific_for_v1(){
if ( 1 === WCML_REST_API::get_api_request_version()){
add_action( 'woocommerce_rest_prepare_product', array( $this, 'append_product_language_and_translations' ) );
add_action( 'woocommerce_rest_prepare_product', array( $this, 'append_product_secondary_prices' ) );
add_action( 'woocommerce_rest_insert_product', array( $this, 'set_product_language' ), 10, 2 );
add_action( 'woocommerce_rest_update_product', array( $this, 'set_product_language' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product', array( $this, 'set_product_custom_prices' ), 10, 2 );
add_action( 'woocommerce_rest_update_product', array( $this, 'set_product_custom_prices' ), 10, 2 );
add_action( 'woocommerce_rest_insert_product', array( $this, 'copy_custom_fields_from_original' ), 10, 1 );
add_action( 'woocommerce_rest_prepare_product', array( $this, 'copy_product_custom_fields' ), 10 , 3 );
add_action( 'woocommerce_rest_insert_shop_order' , array( $this, 'set_order_language' ), 10, 2 );
}
}
/**
* Enforces the language of request as the current language to be able to filter items by language
* @param WP_REST_Server $wp_rest_server
*/
public function set_language_for_request( $wp_rest_server ){
if( isset( $_GET['lang'] ) ){
$request_language = $_GET['lang'];
$active_languages = $this->sitepress->get_active_languages();
if( isset( $active_languages[ $request_language ] ) ){
$this->sitepress->switch_lang( $request_language );
}
}
}
/**
* Prevent WPML redirection when using the default language as a parameter in the url
*/
private function prevent_default_lang_url_redirect(){
$exp = explode( '?', $_SERVER['REQUEST_URI'] );
if ( ! empty( $exp[1] ) ) {
parse_str( $exp[1], $vars );
if ( isset($vars['lang']) && $vars['lang'] === $this->sitepress->get_default_language() ) {
unset( $vars['lang'] );
$_SERVER['REQUEST_URI'] = $exp[0] . '?' . http_build_query( $vars );
}
}
}
/**
* @param WP_Query $wp_query
*/
public function auto_adjust_included_ids( $wp_query ){
$lang = $wp_query->get('lang');
$include = $wp_query->get('post__in');
if( empty( $lang ) && !empty( $include ) ){
$filtered_include = array();
foreach( $include as $id ){
$filtered_include[] = apply_filters( 'translate_object_id', $id, get_post_type($id), true );
}
$wp_query->set( 'post__in' , $filtered_include );
}
}
/**
* Appends the language and translation information to the get_product response
*
* @param $product_data
*
* @return WP_REST_Response
*/
public function append_product_language_and_translations( $product_data ){
$product_data->data['translations'] = array();
$trid = $this->sitepress->get_element_trid( $product_data->data['id'], 'post_product' );
if( $trid ) {
$translations = $this->sitepress->get_element_translations( $trid, 'post_product' );
foreach ( $translations as $translation ) {
if ( $translation->element_id == $product_data->data['id'] ) {
$product_language = $translation->language_code;
} else {
$product_data->data['translations'][ $translation->language_code ] = $translation->element_id;
}
}
$product_data->data['lang'] = $product_language;
}
return $product_data;
}
/**
* Appends the language and translation information to the get_categories response
*
* @param $product_data
*
* @return WP_REST_Response
*/
public function append_category_language_and_translations( $category_data ){
$category_data->data['translations'] = array();
$trid = $this->sitepress->get_element_trid( $category_data->data['id'], 'tax_product_cat' );
if( $trid ) {
$translations = $this->sitepress->get_element_translations( $trid, 'tax_product_cat' );
foreach ( $translations as $translation ) {
if ( $translation->element_id == $category_data->data['id'] ) {
$category_language = $translation->language_code;
} else {
$category_data->data['translations'][ $translation->language_code ] = $translation->element_id;
}
}
$category_data->data['lang'] = $category_language;
}
return $category_data;
}
/**
* Appends the language and translation information to the get_tags response
*
* @param $product_data
*
* @return WP_REST_Response
*/
public function append_tag_language_and_translations( $tag_data ){
$tag_data->data['translations'] = array();
$trid = $this->sitepress->get_element_trid( $tag_data->data['id'], 'tax_product_tag' );
if( $trid ) {
$translations = $this->sitepress->get_element_translations( $trid, 'tax_product_tag' );
foreach ( $translations as $translation ) {
if ( $translation->element_id == $tag_data->data['id'] ) {
$tag_language = $translation->language_code;
} else {
$tag_data->data['translations'][ $translation->language_code ] = $translation->element_id;
}
}
$tag_data->data['lang'] = $tag_language;
}
return $tag_data;
}
/**
* Appends the secondary prices information to the get_product response
*
* @param $product_data
*
* @return WP_REST_Response
*/
public function append_product_secondary_prices( $product_data ){
if( !empty($this->woocommerce_wpml->multi_currency) && !empty($this->woocommerce_wpml->settings['currencies_order']) ){
$product_data->data['multi-currency-prices'] = array();
$custom_prices_on = get_post_meta( $product_data->data['id'], '_wcml_custom_prices_status', true);
foreach( $this->woocommerce_wpml->settings['currencies_order'] as $currency ){
if( $currency !== wcml_get_woocommerce_currency_option() ){
if( $custom_prices_on ){
$custom_prices = (array) $this->woocommerce_wpml->multi_currency->custom_prices->get_product_custom_prices( $product_data->data['id'], $currency );
foreach( $custom_prices as $key => $price){
$product_data->data['multi-currency-prices'][$currency][ preg_replace('#^_#', '', $key) ] = $price;
}
} else {
$product_data->data['multi-currency-prices'][$currency]['regular_price'] =
$this->woocommerce_wpml->multi_currency->prices->raw_price_filter( $product_data->data['regular_price'], $currency );
if( !empty($product_data->data['sale_price']) ){
$product_data->data['multi-currency-prices'][$currency]['sale_price'] =
$this->woocommerce_wpml->multi_currency->prices->raw_price_filter( $product_data->data['sale_price'], $currency );
}
}
}
}
}
return $product_data;
}
/**
* Sets the product information according to the provided language
*
* @param WC_Product|WP_Post $product
* @param WP_REST_Request $request
*
* @throws WCML_REST_Invalid_Language_Exception
* @throws WCML_REST_Invalid_Product_Exception
* @throws WCML_REST_Generic_Exception
*
*/
public function set_product_language( $product, $request ){
$data = $request->get_params();
if( isset( $data['lang'] ) && in_array( $request->get_method(), array( 'POST', 'PUT' ), true ) ){
$active_languages = $this->sitepress->get_active_languages();
if( !isset( $active_languages[$data['lang']] ) ){
throw new WCML_REST_Invalid_Language_Exception( $data['lang'] );
}
if( isset( $data['translation_of'] ) ){
$trid = $this->sitepress->get_element_trid( $data['translation_of'], 'post_product' );
if( empty($trid) ){
throw new WCML_REST_Invalid_Product_Exception( $data['translation_of'] );
}
}else{
$trid = null;
}
$product_id = $this->get_product_id( $product );
$this->sitepress->set_element_language_details( $product_id, 'post_product', $trid, $data['lang'] );
wpml_tm_save_post( $product_id, get_post( $product_id ), ICL_TM_COMPLETE );
}else{
if( isset( $data['translation_of'] ) ){
throw new WCML_REST_Generic_Exception( __( 'Using "translation_of" requires providing a "lang" parameter too', 'woocommerce-multilingual' ) );
}
}
}
/**
* Sets the category information according to the provided language
*
* @param WP_Post $category
* @param WP_REST_Request $request
*
* @throws WCML_REST_Invalid_Language_Exception
* @throws WCML_REST_Invalid_Category_Exception
* @throws WCML_REST_Generic_Exception
*
*/
public function set_category_language( $category, $request ){
$data = $request->get_params();
if( isset( $data['lang'] ) && in_array( $request->get_method(), array( 'POST', 'PUT' ), true ) ){
$active_languages = $this->sitepress->get_active_languages();
if( !isset( $active_languages[$data['lang']] ) ){
throw new WCML_REST_Invalid_Language_Exception( $data['lang'] );
}
if( isset( $data['translation_of'] ) ){
$trid = $this->sitepress->get_element_trid( $data['translation_of'], 'tax_product_cat' );
if( empty($trid) ){
throw new WCML_REST_Invalid_Category_Exception( $data['translation_of'] );
}
}else{
$trid = null;
}
$category_id = $category->term_id;
$this->sitepress->set_element_language_details( $category_id, 'tax_product_cat', $trid, $data['lang'] );
wpml_tm_save_post( $category_id, get_post( $category_id ), ICL_TM_COMPLETE );
}else{
if( isset( $data['translation_of'] ) ){
throw new WCML_REST_Generic_Exception( __( 'Using "translation_of" requires providing a "lang" parameter too', 'woocommerce-multilingual' ) );
}
}
}
/**
* Sets the tag information according to the provided language
*
* @param WP_Post $tag
* @param WP_REST_Request $request
*
* @throws WCML_REST_Invalid_Language_Exception
* @throws WCML_REST_Invalid_Tag_Exception
* @throws WCML_REST_Generic_Exception
*
*/
public function set_tag_language( $tag, $request ){
$data = $request->get_params();
if( isset( $data['lang'] ) && in_array( $request->get_method(), array( 'POST', 'PUT' ), true ) ){
$active_languages = $this->sitepress->get_active_languages();
if( !isset( $active_languages[$data['lang']] ) ){
throw new WCML_REST_Invalid_Language_Exception( $data['lang'] );
}
if( isset( $data['translation_of'] ) ){
$trid = $this->sitepress->get_element_trid( $data['translation_of'], 'tax_product_tag' );
if( empty($trid) ){
throw new WCML_REST_Invalid_Tag_Exception( $data['translation_of'] );
}
}else{
$trid = null;
}
$tag_id = $tag->term_id;
$this->sitepress->set_element_language_details( $tag_id, 'tax_product_tag', $trid, $data['lang'] );
wpml_tm_save_post( $tag_id, get_post( $tag_id ), ICL_TM_COMPLETE );
}else{
if( isset( $data['translation_of'] ) ){
throw new WCML_REST_Generic_Exception( __( 'Using "translation_of" requires providing a "lang" parameter too', 'woocommerce-multilingual' ) );
}
}
}
/**
* Sets custom prices in secondary currencies for products
*
* @param WC_Product|WP_Post $product
* @param WP_REST_Request $request
*
* @throws WC_API_Exception
*
*/
public function set_product_custom_prices( $product, $request ){
$data = $request->get_params();
if( !empty( $this->woocommerce_wpml->multi_currency ) ){
if( !empty( $data['custom_prices'] ) ){
$product_id = $this->get_product_id( $product );
$original_post_id = $this->sitepress->get_original_element_id_filter( '', $product_id, 'post_product' );
update_post_meta( $original_post_id, '_wcml_custom_prices_status', 1);
foreach( $data['custom_prices'] as $currency => $prices ){
$prices_uscore = array();
foreach( $prices as $k => $p){
$prices_uscore['_' . $k] = $p;
}
$this->woocommerce_wpml->multi_currency->custom_prices->update_custom_prices( $original_post_id, $prices_uscore, $currency );
}
}
}
}
/**
* Set product images
*
* @param WC_Product|WP_Post $product
* @param WP_REST_Request $request
*
* @throws WC_API_Exception
*
*/
public function set_product_images( $product, $request ) {
$data = $request->get_params();
if ( isset( $data['translation_of'] ) ) {
$product_id = $this->get_product_id( $product );
$this->woocommerce_wpml->media->sync_thumbnail_id( $data['translation_of'], $product_id, $data['lang'] );
$this->woocommerce_wpml->media->sync_product_gallery( $data['translation_of'] );
if ( isset( $data['variations'] ) ) {
foreach ( $data['variations'] as $variation_id ) {
$this->woocommerce_wpml->media->sync_variation_thumbnail_id( $this->woocommerce_wpml->products->get_original_product_id( $variation_id ), $variation_id, $data['lang'] );
}
}
}
}
/**
* @param WC_Product|WP_Post $product
*/
public function copy_custom_fields_from_original( $product ){
$product_id = $this->get_product_id( $product );
$original_post_id = $this->sitepress->get_original_element_id_filter( '', $product_id, 'post_product' );
if( $original_post_id !== $product_id ){
$this->sitepress->copy_custom_fields( $original_post_id, $product_id );
}
}
/**
* @param WP_REST_Response $response
* @param mixed $object
* @param WP_REST_Request $request
*
* Copy custom fields explicitly
*
* @return WP_REST_Response
*/
public function copy_product_custom_fields($response, $object, $request){
$data = $request->get_params();
if( isset( $data['id'] ) ) {
$translations = $this->wpml_post_translations->get_element_translations( $data['id'], false, true );
foreach ( $translations as $translation_id ) {
$this->sitepress->copy_custom_fields( $data['id'], $translation_id );
}
}
return $response;
}
/**
* Sets the language for a new order
*
* @param WC_Order|WP_Post $order
* @param WP_REST_Request $request
*
* @throws WCML_REST_Invalid_Language_Exception
*/
public function set_order_language( $order, $request ){
$data = $request->get_params();
if( isset( $data['lang'] ) ){
if( $order instanceof WC_Order ){
$order_id = $order->get_id();
}else{
$order_id = $order->ID;
}
$active_languages = $this->sitepress->get_active_languages();
if( !isset( $active_languages[$data['lang']] ) ){
throw new WCML_REST_Invalid_Language_Exception( $data['lang'] );
}
update_post_meta( $order_id, 'wpml_language', $data['lang'] );
}
}
/**
* @param WC_Order $order
* @param WP_REST_Request $request
*
* @throws WCML_REST_Invalid_Currency_Exception
*/
public function set_order_currency( $order, $request ) {
$data = $request->get_params();
if ( isset( $data['currency'] ) ) {
$order_id = $order->get_id();
$currencies = get_woocommerce_currencies();
if ( ! isset( $currencies[ $data['currency'] ] ) ) {
throw new WCML_REST_Invalid_Currency_Exception( $data['currency'] );
}
update_post_meta( $order_id, '_order_currency', $data['currency'] );
}
}
/**
* @param WC_Product|WP_Post $product
*
* @return int
*/
private function get_product_id( $product ) {
if ( $product instanceof WC_Product ) {
return $product->get_id();
} else {
return $product->ID;
}
}
}
<?php
class WCML_REST_Invalid_Product_Exception extends WC_REST_Exception {
/**
* WCML_REST_Invalid_Product_Exception constructor.
*
* @param int $product_id
*/
public function __construct( $product_id ) {
parent::__construct(
422,
sprintf( __( 'Product not found: %d', 'woocommerce-multilingual' ),
$product_id ),
422
);
}
}
<?php
class WCML_REST_Invalid_Tag_Exception extends WC_REST_Exception {
/**
* WCML_REST_Invalid_Tag_Exception constructor.
*
* @param int $tag_id
*/
public function __construct( $tag_id ) {
parent::__construct(
422,
sprintf( __( 'Tag not found: %d', 'woocommerce-multilingual' ),
$tag_id ),
422
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment