I want to display the value of a custom-field in the content-product.php in woocommerce. I did like this, but the output is only the word "array".
where is my mistake?
Thanks a lot!
rabox
<?php if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
global $product;
// Ensure visibility
if ( empty( $product ) || ! $product->is_visible() ) {
return;
}
?>
<li <?php post_class(); ?>>
<span class="product_additional_info"><?php echo get_post_meta($post-
>ID, ‚additional-info‘, true); ?></span>
I found a piece of code that works here https://wordpress.stackexchange.com/questions/179451/unable-to-display-custom-fields-on-woocommerce-product-pages
It goes like that:
<?php
$custom_fields = get_post_custom($post->ID);
$my_custom_field = $custom_fields["Name of your Field"];
foreach ( $my_custom_field as $key => $value ) {
echo "<strong>$key: </strong> $value <br />";
}
?>
Would be interesting to know why I cannot use the "wordpress-way" of using custom fields.
Woocommerce content-product.php uses global $product; so you can get the product id with $product->get_id()
Now, you can get the value of custom field by passing the product id and custom field name in get_post_meta();
Example: get_post_meta( $product->get_id(), '_your_custom_field', true );
Related
What I'm trying to achieve in WooCommerce is that on the single product page, the Description tab, I'm trying to add the product page title before the word Description.
Here is my current WooCommerce code:
defined( 'ABSPATH' ) || exit;
global $post;
$heading = apply_filters( 'woocommerce_product_description_heading', __( 'Description', 'woocommerce' ) ); ?>
<?php if ( $heading ) : ?>
<h2>PRODUCT PAGE TITLE HERE <?php echo esc_html( $heading ); ?></h2>
<?php endif; ?>
<?php the_content(); ?>
The problem here, however, is that:
I have to overwrite the template file, is it possible via a hook?
The product title is not dynamic.
As a result, id like the tab to go from Description to BLACK NIKE SHOES Description
Example:
Any advice?
You can use the woocommerce_product_{$tab_key}_tab_title composite filter hook. Where $tab_key is in your case description
Use global $product and $product->get_name() to get the product title. This result can then be added to the existing string.
So you get:
function filter_woocommerce_product_description_tab_title( $title ) {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get title and append to existing string
$title = $product->get_name() . ' ' . $title;
}
return $title;
}
add_filter( 'woocommerce_product_description_tab_title', 'filter_woocommerce_product_description_tab_title', 10, 1 );
Optional: to change the WooCommerce product description heading instead, use the woocommerce_product_description_heading filter hook:
function filter_woocommerce_product_description_heading( $heading ) {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get title and append to existing string
$heading = $product->get_name() . ' ' . $heading;
}
return $heading;
}
add_filter( 'woocommerce_product_description_heading', 'filter_woocommerce_product_description_heading', 10, 1 );
I'm working on customizing the search results loop within WordPress. I'm displaying search results of two custom post types: Webinars and Research. I'd like to segment the Webinars and Research into their own sections with a heading for each section.
CURRENT LOOP
<?php
if( have_posts() ){
$types = array('webinars', 'research');
foreach( $types as $type ) {
while( have_posts() ){
the_post();
if( $type == get_post_type() ){
get_template_part('loop-templates/content', 'search');
}
}
rewind_posts();
}
}
?>
Any suggestions on getting all Webinars to live in their own div container, and all Research to live in their own div container?
You could simply specify the post type (doesn't have to be in the loop) for each of them straight in the search template. if you want 2 different templates, 1 for webinars and 1 for research, you could do something like that:
<?php if( have_posts() ){
if ( 'webinars' === get_post_type() ):
echo '<h2>Webinars</h2>';
while( have_posts() ){
the_post();
//Template for webinars
the_title(); echo '<br/>';
};
endif;
if ( 'research' === get_post_type() ):
echo '<h2>Research</h2>';
while( have_posts() ){
the_post();
//Template for research
the_title(); echo '<br/>';
};
endif;
}; ?>
You can also restrict the search parameters to go further using pre_get_posts
from the function.php file:
<?php add_action( 'pre_get_posts', function ( $query ) {
if ( ! is_admin() && $query->is_search() && $query->is_main_query() && in_array ( $query->get( 'post_type' ), array( 'webinars', 'research' ) ) ) {
$query->set( 'post_type', array( 'webinars', 'research' ) );
$query->set( 'posts_per_page', 12 );
};
} ); ?>
You can pretty much do anything just keep in mind that your search page must adapt itself to any search query, don't lock it to one specific post type.
Have a wordpress site with woocommerce.
I'm trying to add descriptions for the categories.
It is only adding a description for the first category and then copies it to the other categories.
In my child-themes functions.php I added:
function add_descript() {
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
global $post;
if ( ! $post->post_excerpt ) {
return;
}
?>
<div itemprop="description">
<?php echo apply_filters( 'woocommerce_short_description', $post->post_excerpt ) ?>
</div> <?php
}
add_action( 'woocommerce_before_subcategory_title', 'add_descript' );
Is there a way to loop through all of the categories and grab and excerpt?
Thanks,
Matt
i created a custom field in a product called course-date. I asissnged it a date e.g Jan 30. This is what I have in the email yet nothing shows.. am i missing something? code edited with new snippet below
<?php
/**
* Customer processing order email
*
* #author WooThemes
* #package WooCommerce/Templates/Emails
* #version 2.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<?php
$items = $order->get_items();
foreach ( $items as $item ) {
$product_name = $item['name'];
$product_id = $item['product_id'];
$product_variation_id = $item['variation_id'];
$course_date=get_post_meta($product_id, 'course-date', true);
//Note $course_date will get overwritten if there are more than one items in the order.
}
?>
<?php do_action('woocommerce_email_header', $email_heading); ?>
<p>This email is to notify you of your recent registration for the <b>Level 1 - Think and Grow Rich Institute Course</b>!</p>
<p>You are registered to attend on:</p>
<p><?php printf( __( '<b>Registration ID:</b> %s', 'woocommerce' ), $order->get_order_number() ); ?></p>
<p><b>Course Registration Date:</b> <?php echo get_post_meta($post->id, 'course-date', true); ?></p>
<p><b>Time:</b> 8am Registration - 9am Event Begins (See Full Schedule)</p>
<p><b>Location:</b> 240 Belfield Rd, Toronto, ON M9W 1H3</p>
<p>If you have any questions please contact us by e-mail: contact#thinkandgrowrichinstitute.com.</p>
<p>Sincerely,<BR/>
The Think and Grow Rich Institute Team</p><BR/>
<p><em><b>"Whatever The Mind Can Conceive and Believe, It Will Achieve."</b> - Napoleon Hill</em></p>
<?php do_action( 'woocommerce_email_before_order_table', $order, $sent_to_admin, $plain_text ); ?>
<?php do_action( 'woocommerce_email_after_order_table', $order, $sent_to_admin, $plain_text ); ?>
<?php do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text ); ?>
<?php do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text ); ?>
<?php do_action( 'woocommerce_email_footer' ); ?>
Hope you get to learn more from this answer and it adds to you knowledge of WooCommerce.
For the Snippet you sent of the "Customer processing order email".
The system is unable to find the value of $_product->id here. So it is not working.
You have to debug it by print the Product id itself in the initial test emails.
If you are unable to get the product id. Here is a bit more information.
An order may have more than one products. So finding the product with the meta fields can be troublesome especially when you are having a question of which product you should show the meta field of.
Easy way is to use the given object $order retrieve the order id from this object then find all the products associated in this order and then find meta field value for those products.
<?php
$items = $order->get_items();
foreach ( $items as $item ) {
$product_name = $item['name'];
$product_id = $item['product_id'];
$product_variation_id = $item['variation_id'];
$course_date=get_post_meta($product_id, 'course-date', true);
if(isset($course_date) && $course_date!=""){
echo "<p><b>Course Registration Date:</b>".$course_date."</p>";
}
}
?>
Let us know whether this gave you any insight of the issue.
Here's an untested example of how to add a string to the "customer_processing_email" without overriding the template. You would add this code to your theme's functions.php and the text should appear prior to the order table.
add_action( 'woocommerce_email_order_details', 'kia_custom_order_details', 5, 4 );
function kia_custom_order_details( $order, $sent_to_admin, $plain_text, $email ){
if( $email->id == "customer_processing_order" ){
$course_date = null;
// borrowing the loop from WisdmLabs's answer
$items = $order->get_items();
foreach ( $items as $item ) {
$product_name = $item['name'];
$product_id = $item['product_id'];
$product_variation_id = $item['variation_id'];
$course_date = get_post_meta($product_id, 'course-date', true);
if( $course_date != '' ) break; //break out of the loop if we find a course date
}
if( $course_date && $plain_text ){
echo "Course Registration Date: " . $course_date . "\n\n";
} else if( $course_date && ! $plain_text ){
echo "<p><b>Course Registration Date:</b> " . $course_date . "</p>" . "/n/n";
}
}
}
Don't forget the different formatting for rich text versus plain text emails. I left most of the formatting for the rest of your text to you as the important part was finding/printing the course date meta.
I still think that using a separate email would be the best approach here, but as far as I can tell you were only missing echoing out $course_date in the right place.
Is there a way to add the page attachment feature to the edit media screen? So if I add/edit a media item, I can also attach/re-attach it to a page.
Here's the code I have so far:
function my_post_submitbox_misc_actions( $id ){
$post = get_post( $id );
if( $post->post_parent > 0 ) {
if( get_post( $post->post_parent ) ) {
$title = _draft_or_post_title( $post->post_parent );
}
?>
<div class="misc-pub-section misc-pub-attachment">
Attached to: <strong><?php echo $title ?></strong>
(<a class="hide-if-no-js" onclick="findPosts.open( ''media[]'', '<?php echo $post->ID ?>' );return false;" href="#the-list"><?php _e( 'Re-Attach' ); ?></a>)
</div>
<?php
} else { ?>
<?php _e( '(Unattached)' ); ?><br />
<a class="hide-if-no-js" onclick="findPosts.open( 'media[]', '<?php echo $post->ID ?>' );return false;" href="#the-list"><?php _e( 'Attach' ); ?></a>
<?php
}
}
add_action( 'attachment_submitbox_misc_actions', 'my_post_submitbox_misc_actions' );
And here's my call to the database:
global $wpdb;
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment'", $parent_id ) );
if ( isset( $attached ) ) {
$location = 'upload.php';
if ( $referer = wp_get_referer() ) {
if ( false !== strpos( $referer, 'upload.php' ) )
$location = $referer;
}
$location = add_query_arg( array( 'attached' => $attached ) , $location );
wp_redirect( $location );
}
I've use these combined functions, in my functions.php file, to add a link in the media library (upload.php in admin area) for each media item in the table to attach/re-attach that item to anything.
// Functions to allow one to re-attach an image to a post
function upload_columns( $columns ) {
// Unset( $columns['parent'] );
$columns['better_parent'] = 'Re-Attach';
return $columns;
}
add_filter( 'manage_upload_columns', 'upload_columns' );
function media_custom_columns( $column_name, $id ) {
$post = get_post($id);
if( $column_name != 'better_parent' )
return;
if( $post->post_parent > 0 ) {
if( get_post( $post->post_parent ) ) {
$title = _draft_or_post_title( $post->post_parent );
}
?>
<strong><?php echo $title ?></strong>, <?php echo get_the_time( __( 'Y/m/d' )); ?>
<br />
<a class="hide-if-no-js" onclick="findPosts.open( 'media[]', '<?php echo $post->ID ?>' );return false;" href="#the-list"><?php _e( 'Re-Attach' ); ?></a>
<?php
}else {
?>
<?php _e( '(Unattached)' ); ?><br />
<a class="hide-if-no-js" onclick="findPosts.open( 'media[]', '<?php echo $post->ID ?>' );return false;" href="#the-list"><?php _e( 'Attach' ); ?></a>
<?php
}
}
add_action( 'manage_media_custom_column', 'media_custom_columns', 10, 2 );
I know this doesn't put the option where you are describing, but it's a start in the right direction.
UPDATE:
Note that I'll leave the above code in case someone wants to have the re-attach option in their library table.
As for your question... Here is the code, explanation to follow:
function my_post_submitbox_misc_actions( $id ) {
global $pagenow, $typenow;
// We only want to run the code on a specific page
if( $pagenow != 'post.php' || $typenow != 'attachment' ) {
return;
}
$post = get_post( $id );
if( $post->post_parent > 0 ) {
if( get_post( $post->post_parent ) ) {
$title = _draft_or_post_title( $post->post_parent );
}
?>
<div class="misc-pub-section misc-pub-attachment">
Attached to: <strong><?php echo $title ?></strong>
( <a class="hide-if-no-js" onclick="findPosts.open('action','find_posts');return false;" href="#"><?php _e( 'Re-Attach' ); ?></a> )
</div>
<?php
} else {
_e( '(Unattached)' ); ?><br />
<a class="hide-if-no-js" onclick="findPosts.open('action','find_posts');return false;" href="#"><?php _e( 'Attach' ); ?></a>
<?php
}
}
add_action( 'attachment_submitbox_misc_actions', 'my_post_submitbox_misc_actions' );
// Function to call the find_posts_div pop up OUTSIDE the post form
function my_post_submitbox_misc_form() {
global $pagenow, $typenow;
// We only want to run the code on a specific page
if( $pagenow != 'post.php' || $typenow != 'attachment' ) {
return;
}
// Enqueue our scripts
wp_enqueue_style('thickbox');
wp_enqueue_script('thickbox'); // needed for find posts div
wp_enqueue_script('media');
wp_enqueue_script('wp-ajax-response');
?>
<form name="plugin_form" id="plugin_form" method="post" action="/wp-content/themes/<?php echo get_template() . '/test.php'; ?>">
<?php
wp_nonce_field('plugin_nonce');
find_posts_div();
?>
</form>
<?php
}
add_filter('admin_footer','my_post_submitbox_misc_form');
BREAKDOWN
The first function is very similar to what you already have in your code above. I believe the only change I made was to add the check to make sure we only run this code on the edit attachment page. You might need to tweak this, as I tested it, but not fully.
I also changed the way we call findPosts.open(). We now pass a variable called 'action' and set it's value to 'find_posts' so we can check for it later...
So the first function simply shows the post the attachment is already attached to, and lets you re-assign it if desired... or shows you an option to just attach it. The re-attach and attach are just links that, when clicked, launch findPosts.open() which looks for a hidden div/inputs on the page... we haven't created those yet.
The second function is the key... first, you do need to enqueue scripts and one style. The import piece of code here is the find_posts_div() call. This is what makes the magic happen, but all this does is creates hidden divs and form fields in a pop-up, just waiting to be called (our anchors in the first function). This NEEDS TO BE in a separate function so that we can use add_filter to call the function OUTSIDE OF the post form.
At first I tried to have it all together in one function. The browser strips out our <form> tag because we are attempting to place a form inside another form (the post form), and that's a no no. So by calling it in the admin_footer, we load the code outside the form.
Wrapping the find_posts_div() in a form allows us to submit the results of that form to where ever we want, to do whatever we want with it. In our case, we create a new page (test.php) and submit the results there, so we can do what we need.
So far, the test.php page is as follows:
<?php
echo '<pre>';print_r($_POST);echo '</pre>';
die();
?>
This will show you all the values of $_POST... feel free to add more hidden values and what not, but the 'found_post_id' value is the post id from the selected value from the pop up. Then you can check out lines 103 - 141 of upload.php to find code to do the actual re-attach. There might be a hook or something better, but I didn't have time to look.
Hope this helps!
So after a little help from Daniel and some research, I was finally able to make it work! Here's how my code looks now:
function spd_submitbox_misc_actions( $id ) {
global $pagenow, $typenow;
// We only want to run the code on a specific page
if( $pagenow != 'post.php' || $typenow != 'attachment' ) {
return;
}
$post = get_post( $id );
if( $post->post_parent > 0 ) {
if( get_post( $post->post_parent ) ) {
$title = _draft_or_post_title( $post->post_parent );
}
?>
<div class="misc-pub-section misc-pub-attachment">
Attached to: <strong><?php echo $title ?></strong>
<a class="hide-if-no-js" onclick="findPosts.open('action','find_posts');return false;" href="#"><?php _e( ' (Re-Attach) ' ); ?></a>
</div>
<?php
} else { ?>
<div class="misc-pub-section misc-pub-attachment">
Attached to: (Unattached) <a class="hide-if-no-js" onclick="findPosts.open('action','find_posts');return false;" href="#"><?php _e( 'Attach' ); ?></a>
</div>
<?php
}
}
add_action( 'attachment_submitbox_misc_actions', 'spd_submitbox_misc_actions' );
// Function to call the find_posts_div pop up OUTSIDE the post form
function spd_post_submitbox_misc_form() {
global $pagenow, $typenow;
// We only want to run on edit media page
if( $pagenow != 'post.php' || $typenow != 'attachment' )
return;
// Enqueue our scripts
wp_enqueue_style('thickbox');
wp_enqueue_script('thickbox'); // needed for find posts div
wp_enqueue_script('media');
wp_enqueue_script('wp-ajax-response');
$send_to = get_template_directory_uri() . '/inc/spdfunctions/spd_post_actions.php';
?>
<form name="attach-to-post" method="post" action="<?php echo $send_to; ?>">
<?php find_posts_div(); ?>
<input type="hidden" name="attach-to-post" value="attach" />
<input type="hidden" name="attachment-id" value="<?php the_ID(); ?>" />
</form>
<?php
}
add_filter('admin_footer','spd_post_submitbox_misc_form');
Then to process the submission:
if ( $_REQUEST['action'] && isset( $_POST['attach-to-post'] ) ) {
$location = $_SERVER['DOCUMENT_ROOT'];
include( $location . '/wp-load.php' );
$parent_id = $_POST['found_post_id'];
$attach_id = (int) $_POST['attachment-id'];
$attached = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( %d )", $parent_id, $attach_id ) );
//redirect back to edit media screen
if ( isset( $attached ) ) {
$referer = wp_get_referer();
$location = add_query_arg( array( 'attached' => $attached ) , $referer );
wp_redirect( $location );
}
}
Thanks again, Daniel, for all your help. It was very much appreciated!