Woocommerce searchable product custom field - wordpress

my products have two important codes which are the EAN-13 and its model number. I wrote the EAN-13 in the SKU and the products model number in a custom field. The SKU is perfectly searchable but the data is not.
Is there any way to make a product custom field searchable from the back-end office?
Please help! Thanks in advance!

When I was searching for almost similar problem I've found solution here https://dominykasgel.com/extend-search-custom-post-types-wordpress-admin/, here's my code for functions.php in child theme:
function extend_admin_search( $query ) {
$custom_fields = array(
"_file_name",
);
if( ! is_admin() )
return;
$search_term = $query->query_vars['s'];
$query->query_vars['s'] = '';
$query->set('_meta_or_title', $search_term);
if ( $search_term != '' ) {
$meta_query = array( 'relation' => 'OR' );
foreach( $custom_fields as $custom_field ) {
array_push( $meta_query, array(
'key' => $custom_field,
'value' => $search_term,
'compare' => 'LIKE'
));
}
$query->set( 'meta_query', $meta_query );
};
}
add_action( 'pre_get_posts', 'extend_admin_search', 6, 2);
add_action( 'pre_get_posts', function( $q )
{
if( $title = $q->get( '_meta_or_title' ) )
{
add_filter( 'get_meta_sql', function( $sql ) use ( $title )
{
global $wpdb;
// Only run once:
static $nr = 0;
if( 0 != $nr++ ) return $sql;
// Modified WHERE
$sql['where'] = sprintf(
" AND ( %s OR %s ) ",
$wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
);
return $sql;
}, 12, 1);
}
}, 12, 1);
DISCLAIMER: it was used a few years ago, so I can't be sure if it works fine for now.

Related

Exclude grouped products children in woocommerce, without exclude simple products

THis code is working but I need to include single product without a parent grouped product associated
add_action( 'woocommerce_product_query', 'remove_grouped_children' );
function remove_grouped_children( $q ) {
//get current loop query
$taxonomy_query = $q->get('tax_query') ;
//appends the grouped products condition
$taxonomy_query['relation'] = 'AND';
$taxonomy_query[] = array(
'taxonomy' => 'product_type',
'field' => 'slug',
'terms' => array('grouped','variable')
);
$q->set( 'tax_query', $taxonomy_query );
}
This a walk-around, but finally work.
function wr_convert_array_to_ids(){
$products = wr_get_grouped_product_children();
$post_ids = array();
foreach ($products as $product){
foreach ($product as $id){
array_push($post_ids,$id);
}
}
return $post_ids;
}
function wr_get_grouped_product_children(){
global $wpdb;
$products = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM $wpdb->prefix" . "postmeta WHERE meta_key = %s", '_children'),ARRAY_A
);
$products_id = array();
foreach($products as $product){
array_push($products_id, unserialize($product['meta_value']));
}
return $products_id;
}
function wr_custom_get_posts( $query ) {
if ( is_admin() || ! $query->is_main_query() )
return;
if ( $query->is_archive() || $query->is_shop()) {
$query->set( 'post__not_in', wr_convert_array_to_ids() );
}
}
add_action( 'pre_get_posts', 'wr_custom_get_posts', 1 );
Because the children of grouped products live in the post-meta table below the meta_key _children that is saved as a serialized array, the first thing is to get all the children, then save them in an array and call the 'pre_get_posts' action to exclude those identifiers.

How to remove private posts from next / previous posts in WordPress?

I have implemented Vue.js single page application in a WordPress theme (wue-theme.app) and want to navigate through the blog posts by next / previous links from within the single-post template. But I struggle to remove private posts from the links - there are no WP_Query options available. So how can I navigate through the posts with the status "publish" only?
Unfortunately I couldn't find any documented "official" ways to do this. So I "hacked" a bit the default SQL query which you can fortunately apply a filter on, and have removed the "private" post_status from the query. This is the full custom code for the "post" post type you have to place in your functions.php:
add_filter( 'rest_prepare_post', 'technomad_post_api_hook', 10, 3 );
function technomad_post_api_hook( $response ) {
if ( isset( $_REQUEST["slug"] ) ) {
add_filter( "get_next_post_where", function($query, $in_same_cat, $excluded_categories, $taxonomy, $post){
$query = str_replace("OR p.post_status = 'private'", "", $query);
return $query;
}, 100, 5 );
add_filter( "get_previous_post_where", function($query, $in_same_cat, $excluded_categories, $taxonomy, $post){
$query = str_replace("OR p.post_status = 'private'", "", $query);
return $query;
}, 100, 5 );
$next = get_adjacent_post( false, '', false );
$previous = get_adjacent_post( false, '', true );
if ( is_a( $next, 'WP_Post' ) ) {
$response->data['next'] = array(
"id" => $next->ID,
"slug" => $next->post_name,
"title" => $next->post_title,
);
} else {
$response->data['next'] = null;
}
if ( is_a( $previous, 'WP_Post' ) ) {
$response->data['previous'] = array(
"id" => $previous->ID,
"slug" => $previous->post_name,
"title" => $previous->post_title,
);
} else {
$response->data['previous'] = null;
}
}
}
You can also just return your own custom query instead of str_replace():
return $wpdb->prepare( "WHERE p.post_title > %s AND p.post_type = %s AND ( p.post_status = 'publish' )", $post->post_title, $post->post_type );

How to display woocommerce PRICE on product's BODY text - using SHORTCODE?

I'm writing some details of each prodcuts (short/long description) on woocommerce.
i'd like to insert a SHORTCODE inside the description that shows the current PRICE (sale / regular).
it should look something like that on the backend:
"Buy it now, for only [wc_price] $"
is there any shortcode i can use for that?
This is one the most simple snippet that does what you want without the need of inputting the id manually:
function my_shortcode_product_price() {
$html = '';
global $product;
$price = wc_get_price_to_display( $product, array( 'price' => $product->get_price() ) );
$args = array(
'ex_tax_label' => false,
'currency' => 'USD',
'decimal_separator' => '.',
'thousand_separator' => ' ',
'decimals' => 2,
'price_format' => '%2$s %1$s',
);
$html = "<span>" . wc_price( $price, $args ) . "</span>";
return $html;
}
add_shortcode( 'product_price', 'my_shortcode_product_price' );
The above code goes in the functions.php file of your active theme. After that you can use the shortcode like this:
[product_price]
Here You Go: add this code in your function.php
function short_code_woo_comm_desc( $atts ) {
$atts = shortcode_atts( array(
'id' => null
), $atts, 'tag_for_short_code_price' );
if ( empty( $atts[ 'id' ] ) ) {
return '';
}
$product = wc_get_product( $atts['id'] );
if ( ! $product ) {
return '';
}
return $product->get_price_html();
}
add_shortcode( 'tag_for_short_code_price', 'short_code_woo_comm_desc' );
Use:
[tag_for_short_code_price id="101"]

How to make custom form-tag in contact form 7 required

So i make custom form-tag in contact form 7! It is a drop down with list of my courses and now I want to make it required because that is the main thing in whole form.
So can someone give me a tip how to do that?
When I do the [myCustomField* course-name class:custom-field]
It does not working with *
So if someone can help it will be great!
I have been working on this myself this afternoon and I do not think Mahmoud has added everything that is needed to get the validation working well and the messages showing up.
using what I have learnt from the posts on contact form 7 here:
https://contactform7.com/2015/01/10/adding-a-custom-form-tag
https://contactform7.com/2015/02/27/using-values-from-a-form-tag/
and looking at this file in the plugin: contact-form-7/modules/select.php which helped a lot.
I think this will work better and needs to be added to your functions.php file in your child-theme.
add_action( 'wpcf7_init', 'custom_add_form_tag_myCustomField' );
function custom_add_form_tag_myCustomField() {
wpcf7_add_form_tag( array( 'myCustomField', 'myCustomField*' ),
'custom_myCustomField_form_tag_handler', true );
}
function custom_myCustomField_form_tag_handler( $tag ) {
$tag = new WPCF7_FormTag( $tag );
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
$atts['aria-invalid'] = $validation_error ? 'true' : 'false';
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$myCustomField = '';
$query = new WP_Query(array(
'post_type' => 'CUSTOM POST TYPE HERE',
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
));
while ($query->have_posts()) {
$query->the_post();
$post_title = get_the_title();
$myCustomField .= sprintf( '<option value="%1$s">%1$s</option>',
esc_html( $post_title ) );
}
wp_reset_query();
$myCustomField = sprintf(
'<span class="wpcf7-form-control-wrap %1$s"><select %2$s>%3$s</select>%4$s</span>',
sanitize_html_class( $tag->name ),
$atts,
$myCustomField,
$validation_error
);
return $myCustomField;
}
That is how we create the custom tag. The important differences here are the addition of the $validation_error variables as wells the aria-required and aria-invalid data. It is also important to include the $validation_error in the final output so that we can see the validation messages being created.
Then to finish it off we need to add some validation via filters.
There is no documentation on this yet, but I used the functions from the select.php and altered them to what I needed.
/* Validation filter */
add_filter( 'wpcf7_validate_myCustomField', 'wpcf7_myCustomField_validation_filter', 10, 2 );
add_filter( 'wpcf7_validate_myCustomField*', 'wpcf7_myCustomField_validation_filter', 10, 2 );
function wpcf7_myCustomField_validation_filter( $result, $tag ) {
$tag = new WPCF7_FormTag( $tag );
$name = $tag->name;
if ( isset( $_POST[$name] ) && is_array( $_POST[$name] ) ) {
foreach ( $_POST[$name] as $key => $value ) {
if ( '' === $value ) {
unset( $_POST[$name][$key] );
}
}
}
$empty = ! isset( $_POST[$name] ) || empty( $_POST[$name] ) && '0' !== $_POST[$name];
if ( $tag->is_required() && $empty ) {
$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
}
return $result;
}
This code should also go in your functions.php file just under the code for the custom CF7 tag.
Here the filter's first string $tag should match with the class that is being generated in the custom CF7 tag so if your custom tag->type = 'myCustomField' then the $tag of the filter must include the name, like so wpcf7_validate_myCustomField as well as the required version of it, wpcf7_validate_myCustomField*.
I hope that helps anyone else looking for this.
If you want even more of the options available from the backend of Contact Form 7 check the select.php file as it lays it out quite nicely on how to get each option and include it.
You can use [select*] to output a required drop-down menu.
[select* course-name include_blank "English" "Math"]
Check https://contactform7.com/checkboxes-radio-buttons-and-menus/
EDIT:
So you have your own shortcode [myCustomField]. To make two versions of your shortcode as [myCustomField] and [myCustomField*] you have to pass both shortcodes to your function as the following:
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_mycustomfield' );
function wpcf7_add_form_tag_mycustomfield() {
wpcf7_add_form_tag( array( 'myCustomField', 'myCustomField*'),
'wpcf7_mycustomfield_form_tag_handler', array( 'name-attr' => true ) );
}
function wpcf7_mycustomfield_form_tag_handler( $tag ) {
$tag = new WPCF7_FormTag( $tag );
if ( empty( $tag->name ) ) {
return '';
}
$atts = array();
$class = wpcf7_form_controls_class( $tag->type );
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$html = sprintf( '<your-tag %s></your-tag>', $atts );
return $html;
}
Then, you can use it:
[myCustomField course-name class:custom-field]
or
[myCustomField* course-name class:custom-field]
References:
https://contactform7.com/2015/01/10/adding-a-custom-form-tag
https://contactform7.com/2015/02/27/using-values-from-a-form-tag/

Woocommerce product admin sort by stock

Is there anyway I can sort by stock? Since it reads 'Stock x 30' it would be helpful if I could sort by high or low. Is there any code I can add to the functions.php to enable that feature?
easy enough... it can be accomplished with this code...
add_filter( 'manage_edit-product_sortable_columns', 'rei_product_sortable_columns' );
function rei_product_sortable_columns( $columns ) {
$custom = array(
'is_in_stock' => 'is_in_stock'
);
return wp_parse_args( $custom, $columns );
}
but this would just sort what the stock column has... example, 'in stock' or 'out of stock'
To have a custom sort, (for example, using the stock number), you may follow the instruction on this blog post.
Working version as of: Year 2022, WP 5.9.3, WC 6.4.1:
// make quantity column sortable
function rei_product_sortable_columns( $columns )
{
$custom = array(
'is_in_stock' => 'stock_disponible'
);
return wp_parse_args( $custom, $columns );
}
add_filter( 'manage_edit-product_sortable_columns', 'rei_product_sortable_columns' );
// only load on edit.php page
function my_edit_movie_load() {
add_filter( 'request', 'my_sort_movies' );
}
add_action( 'load-edit.php', 'my_edit_movie_load' );
// do the sorting
function my_sort_movies( $vars )
{
/* Check if we're viewing the 'product' post type. */
if ( isset( $vars['post_type'] ) && 'product' == $vars['post_type'] )
{
/* Check if 'orderby' is set to 'stock_disponible'. */
if ( isset( $vars['orderby'] ) && 'stock_disponible' == $vars['orderby'] )
{
/* Merge the query vars with our custom variables. */
$vars = array_merge(
$vars,
array(
'meta_key' => '_stock',
'orderby' => 'meta_value_num'
)
);
}
}
return $vars;
}

Resources