How to add "Brand" element to schema markup (WooCommerce microdata) - woocommerce

Is there a possibility to add information about product brand in WooCommerce product schema?
I tried to use product schema plugins, but they don't fit my needs and break existing schema or add a second one to the product code, so the best solution is to modify it manually. I tried to use this snippet, but it doesn't create the correct markup structure:
add_filter( 'woocommerce_structured_data_product_offer', 'nt_woocommerce_structured_data_product_offer', 10, 2 );
function nt_woocommerce_structured_data_product_offer( $markup, $product ) {
$markup[ 'brand' ] = wc_get_product()->get_attribute('pa_brand');
return $markup;
}
I need this snippet to create something like this:
"brand": {
"#type": "Thing",
"name": "ACME"
}
but it creates such a markup, which is not validated by Google:
"brand":"ACME"
Do you have any ideas about how to create correct markup by using a php snippet?

You need to use a different filter woocommerce_structured_data_product and set the brand using an array.
add_filter( 'woocommerce_structured_data_product', 'nt_woocommerce_structured_data_product_offer', 10, 2 );
function nt_woocommerce_structured_data_product_offer( $markup, $product ) {
$markup[ 'brand' ] = array(
'#type' => 'Thing',
'name' => wc_get_product()->get_attribute('pa_brand'),
);
return $markup;
}

Related

Custom product attributes is blank even though I add it [duplicate]

The products in my clients website require certain attributes which I have added via Products -> Attributes in the Wordpress administration. In this import script I'm coding I need to use the function update_post_meta($post_id, $meta_key, $meta_value) to import the proper attributes and values.
Currently I have the function like so:
update_post_meta( $post_id, '_product_attributes', array());
However I'm not sure how to properly pass along the attributes and their values?
Right so it took me a while to figure it out myself but I finally managed to do this by writing the following function:
// #param int $post_id - The id of the post that you are setting the attributes for
// #param array[] $attributes - This needs to be an array containing ALL your attributes so it can insert them in one go
function wcproduct_set_attributes($post_id, $attributes) {
$i = 0;
// Loop through the attributes array
foreach ($attributes as $name => $value) {
$product_attributes[$i] = array (
'name' => htmlspecialchars( stripslashes( $name ) ), // set attribute name
'value' => $value, // set attribute value
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
// Example on using this function
// The attribute parameter that you pass along must contain all attributes for your product in one go
// so that the wcproduct_set_attributes function can insert them into the correct meta field.
$my_product_attributes = array('hdd_size' => $product->hdd_size, 'ram_size' => $product->ram_size);
// After inserting post
wcproduct_set_attributes($post_id, $my_product_attributes);
// Woohay done!
I hope this function will help other people if they need to import multiple attributes pro-grammatically in WooCommerce!
I tried Daniel's answer, and it didn't work for me. It might be that the Wordpress/Woocommerce code has changed since, or perhaps I didn't quite understand how to do it, but either way that code did nothing for me. After a lot of work using it as a base, however, I came up with this snippet of code and put it on my theme's functions.php:
function wcproduct_set_attributes($id) {
$material = get_the_terms( $id, 'pa_material');
$material = $material[0]->name;
// Now update the post with its new attributes
update_post_meta($id, '_material', $material);
}
// After inserting post
add_action( 'save_post_product', 'wcproduct_set_attributes', 10);
With this, I can take what I set as "material" on my WooCommerce install as a custom attribute and add it to the formal meta as _material. This in turn allows me to use another snippet of code so the WooCommerce search function extends to meta fields, meaning I can search for a material in the WooCommerce search field and have all items with that material appear.
I hope this is useful to somebody.
#Daniels's answer works, won't decide on right or wrong, however if you want to add the values as a taxonomy term under attributes you have to adapt the code as below (set is_taxonomy = 1). Otherwise Woocommerce sees it as custom meta field(?). It still adds the value under attributes. This will only work for strings. For values that are arrays the code has to be adapted.
Additionally it uses the wp_set_object_terms that #Anand suggests as well. I was using that, because all the documentation I could find led to believe that had to be used. However if one only uses the wp_set_object_terms then I couldn't see the attributes in the edit product screen. Using the information from both answers and reading on the subject resulted in the solution.
You will need to tweak the code for things such as product variations.
/*
* Save Woocommerce custom attributes
*/
function save_wc_custom_attributes($post_id, $custom_attributes) {
$i = 0;
// Loop through the attributes array
foreach ($custom_attributes as $name => $value) {
// Relate post to a custom attribute, add term if it does not exist
wp_set_object_terms($post_id, $value, $name, true);
// Create product attributes array
$product_attributes[$i] = array(
'name' => $name, // set attribute name
'value' => $value, // set attribute value
'is_visible' => 1,
'is_variation' => 0,
'is_taxonomy' => 1
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
Then call the function:
$custom_attributes = array('pa_name_1' => $value_1, 'pa_name_2' => $value_2, 'pa_name_3' => $value_3);
save_wc_custom_attributes($post_id, $custom_attributes);
Thank you for posting the code Daniel & Anand. It helped me a great deal.
Don't know if this is the "correct" way to do this... But I needed a function to add ACF repeater fields with a date value as a attribute on post save, so this was the function I came up with:
add_action( 'save_post', 'ed_save_post_function', 10, 3 );
function ed_save_post_function( $post_ID, $post, $update ) {
//print_r($post);
if($post->post_type == 'product')
{
$dates = get_field('course_dates', $post->ID);
//print_r($dates);
if($dates)
{
$date_arr = array();
$val = '';
$i = 0;
foreach($dates as $d)
{
if($i > 0)
{
$val .= ' | '.date('d-m-Y', strtotime($d['date']));
}
else{
$val .= date('d-m-Y', strtotime($d['date']));
}
$i++;
}
$entry = array(
'course-dates' => array(
'name' => 'Course Dates',
'value' => $val,
'position' => '0',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
)
);
update_post_meta($post->ID, '_product_attributes', $entry);
}
}
}
Hope this helps someone.

How to filter posts modified after specific date in Wordpress API v2

I am trying to fetch(filter) the posts modified after specific date through WordPress REST API 2.0-beta15 & WordPress v4.8.3 and update that with the existing posts in my client app.
Using after and before query params provided by WordPress I can filter posts based on date instead of modified field.
I have tried /wp-json/wp/v2/posts?filter[date_query][0][column]=post_modified_gmt&filter[date_query][0][after]=1+month+ago using this https://github.com/WP-API/rest-filter as mentioned in this issue, but this date_query filter is also not working now.
I need any option like
http://bankersdaily.in/wp-json/wp/v2/posts?modified_after=2017-10-31T13:32:10&_envelope
http://bankersdaily.in/wp-json/wp/v2/posts?after=2017-10-31T13:32:10&field=modified&_envelope
References:
https://developer.wordpress.org/rest-api/reference/posts/#list-posts
https://codex.wordpress.org/Class_Reference/WP_Query?#Date_Parameters
It looks like it's not supported, skimming through the docs
Here are some workarounds:
1) Custom modified_after rest query parameter
We can add the modified_after rest query parameter for the post post type with:
add_filter( 'rest_post_collection_params', function( $query_params ) {
$query_params['modified_after'] = [
'description' => __( 'Limit response to posts published after a given ISO8601 compliant date.' ),
'type' => 'string',
'format' => 'date-time',
];
return $query_params;
} );
and then modify the rest post query accordingly with:
add_filter( 'rest_post_query', function( $args, $request ) {
if( isset( $request['modified_after'] ) && ! isset( $request['after'] ) ) {
$args['date_query'][0]['after'] = $request['modified_after'];
$args['date_query'][0]['column'] = 'post_modified';
}
return $args;
}, 10, 2 );
where we let after take priority over modified_after.
Example:
/wp-json/wp/v2/posts??modified_after=2017-11-07T00:00:00
Notes:
We might have used modified_gmt_after for the post_modified_gmt column.
It might be better to use a more unique name than modified_after to avoid a possible future name collision.
To extend this to other post types, we can use the rest_{$post_type}_collection_params and the rest_{$post_type}_query filters.
Another option is to create a custom endpoint and parameters, that's a more work to do there. It's of course a question if we should add a custom parameter to the current rest api. In some cases it should be ok, as we're not removing or modifying the response, or changing how other parameters work.
2) Custom date_query_column rest query parameter
Another approach would be to introduce a custom date_query_column rest query parameter:
add_filter( 'rest_post_query', function( $args, $request ) {
if ( ! isset( $request['before'] ) && ! isset( $request['after'] ) )
return $args;
if( isset( $request['date_query_column'] ) )
$args['date_query'][0]['column'] = $request['date_query_column'];
return $args;
}, 10, 2 );
add_filter( 'rest_post_collection_params', function( $query_params ) {
$query_params['date_query_column'] = [
'description' => __( 'The date query column.' ),
'type' => 'string',
'enum' => [ 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt', 'comment_date', 'comment_date_gmt' ],
];
return $query_params;
} );
that would be available if either after or before parameters are set.
Example:
/wp-json/wp/v2/posts??after=2017-11-07T00:00:00&date_query_column=post_modified
Hope it helps!
Native Support - WordPress 5.7
As of WordPress 5.7, support has been added for querying by the post modified date rather than the published date. Custom workarounds are no longer required.
Usage:
/wp-json/wp/v2/posts??modified_after=2021-01-01T00:00:00Z
Notes: https://make.wordpress.org/core/2021/02/23/rest-api-changes-in-wordpress-5-7/
I have created a WordPress plugin WP REST API – Filter posts date wise using given column, those who need can use this.
Using this plugin we can specify the column(any of date, date_gmt, modified, modified_gmt) as query parameter date_query_column to query against value(s) given in before and/or after query parameters.
Usage
Use the date_query_column parameter on any post endpoint such as /wp/v2/posts or /wp/v2/pages in combination with before and/or after parameter.
/wp-json/wp/v2/posts??after=2017-11-08T13:07:09&date_query_column=modified
Github Repository of the same.

Adding a link in post-type list

I want to add a custom link in the posts of my post-type with the filter post_row_actions but there's no additional link.
I use this code :
function custom_duplicate_link( $actions, $post ) {
$actions['duplicate'] = 'Duplicate';
return $actions;
}
add_filter( 'post_row_actions', 'custom_duplicate_link', 10, 2 );
Have I missed anything? Or does anyone know why it isn't working?
Check your custom post type:
'hierarchical' => TRUE,
The filter 'post_row_actions' only work with post types not hierarchical.
The filter 'page_row_actions' only work with post types hierarchical.

Add ability to filter custom post type by custom fields?

I'm using both the "Types" and the "Advanced Custom Fields" plugins for Wordpress. With "Types" I have created a custom post and when you click "add new" you create a new post by filling out the text areas and drop-downs that I created using "Advanced Custom Fields".
Currently, when I click on my post in the sidebar there is a filter to sort my subposts (sorry for the horrendous lack of proper terminology; I'm new to wordpress) by date added. I also want to be able to sort by some of the custom fields I have created in the dropdown box.
Also, there are two columns labelled "title" and "date". Is it possible to add a couple more?
Writing PHP
You can write some PHP as outlined by the developer of Advanced Custom Fields (Elliot Condon) in this blog post.
The following code taken from the post will display an image and a true / false field in the admin screen:
function my_page_columns($columns)
{
$columns = array(
'cb' => '<input type="checkbox" />',
'thumbnail' => 'Thumbnail',
'title' => 'Title',
'featured' => 'Featured',
'author' => 'Author',
'date' => 'Date',
);
return $columns;
}
function my_custom_columns($column)
{
global $post;
if($column == 'thumbnail')
{
echo wp_get_attachment_image( get_field('page_image', $post->ID), array(200,200) );
}
elseif($column == 'featured')
{
if(get_field('featured'))
{
echo 'Yes';
}
else
{
echo 'No';
}
}
}
add_action("manage_pages_custom_column", "my_custom_columns");
add_filter("manage_edit-page_columns", "my_page_columns");
To be able to sort the true / false column you can use the following code as outlined in the post:
function my_column_register_sortable( $columns )
{
$columns['featured'] = 'featured';
return $columns;
}
add_filter("manage_edit-page_sortable_columns", "my_column_register_sortable" );
Using a Plugin
Alternatively, without any PHP programming, you can do this using the Admin Columns by Codepress plugin.

Show custom field on order in woocommerce

Im working on a webshop and follwoing this tutorial http://wcdocs.woothemes.com/snippets/tutorial-customising-checkout-fields-using-hooks-and-filters/ to add some customes fields to my billing.
// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
$fields['billing']['billing_gls_name'] = array(
'label' => __('Name for pickup person', 'woocommerce'),
'placeholder' => _x('Name', 'placeholder', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true
);
return $fields;
}
This adds my field. So far so good. So my problem is:
How can I view this new field in the orders view? Details for billing only show the usual billing fields.
The first answer (Cesar) was CLOSE to being correct. In case anyone ever comes across this old post trying to find out the same thing, below is the code needed to insert into your functions.php file after the code given by the original poster, tailored to his/her variables as provided. Note that they use the field name "billing_gls_name" and that this is referenced in our new function as "_billing_gls_name". The extra "_" at the beginning is necessary. This works on Wordpress 3.5.1 running WooCommerce 2.0.3.
function your_custom_field_function_name($order){
echo "<p><strong>Name of pickup person:</strong> " . $order->order_custom_fields['_billing_gls_name'][0] . "</p>";
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'your_custom_field_function_name', 10, 1 );
After defining your custom field (that you did in your code mentioned above), add the code mentioned below to:
Process your field
Save it in the database as Order meta data
Display it in the 'Order details' in the Woocommerce->Orders section
Process your field:
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
if (!$_POST['billing']['billing_gls_name']) {
wc_add_notice(__('Please tell us the Location Type that we are billing to.'), 'error');
}
}
Save Field in the DB as Order Meta Data:
add_action('woocommerce_checkout_update_order_meta','my_custom_checkout_field_update_order_meta');
function my_custom_checkout_field_update_order_meta($order_id) {
if (!empty($_POST['billing']['billing_gls_name'])) {
update_post_meta($order_id, 'Billing Gls Name', esc_attr($_POST['billing']['billing_gls_name_type']));
}
}
And finally display it in the Order details screen:
add_action('woocommerce_admin_order_data_after_billing_address', 'my_custom_billing_fields_display_admin_order_meta', 10, 1);
function my_custom_billing_fields_display_admin_order_meta($order) {
echo '<p><strong>' . __('Billing Gls Name') . ':</strong><br> ' . get_post_meta($order->id, '_billing_gls_name', true) . '</p>';
}
Adding the action woocommerce_admin_order_data_after_billing_address you can insert some data after billing info. Custom fields are under $order->order_custom_fields array.
function display_rfc_in_order_metabox($order){
echo "<p><strong>RFC:</strong> {$order->order_custom_fields['_billing_rfc'][0]}</p>";
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'rxm_details_to_order', 10, 1 );

Resources