Add attachments based on user role to WooCommerce new user registration email - php

I want to add two pdf files to the new user registration e-mail of WooCommerce.
Because I have two specific user roles customer and seller.
I want to send all new sellers two pdf files from paths $path1 and $path3 and all new customers two pdf files from paths $path2 and $path3.
I tried this in my functions.php
function attach_to_email ( $attachments, $userrole ) {
$root = ABSPATH;
$path1 = $root . '/media/AGB H.pdf';
$path2 = $root . '/media/AGB K.pdf';
$path3 = $root . '/media/W.pdf';
if ( $userrole === 'seller' ) {
$attachments[] = $path1;
$attachments[] = $path3;
} else {
$attachments[] = $path2;
$attachments[] = $path3;
}
return $attachments;
}
add_filter( 'woocommerce_email_attachments', 'attach_to_email', 10, 2 );
In the e-mail template for sellers I call:
do_action( 'woocommerce_email_attachments', null, 'seller' );
But in the function, I always enter the else part and not the if-part. In addition, all e-mails are attached with the else-files now, not only the registration e-mails. Any ideas?

To only assign the attachments to the registration e-mail, you can use:
The $email_id, where this is equal to customer_new_account
For the attachement path, linked to the theme, you can use:
get_stylesheet_directory() for a child theme
get_template_directory() for a parent theme
I would also recommend not to use spacing in the file name of the pdf file
You can then assign the correct attachments based on the user role
So you get:
function filter_woocommerce_email_attachments( $attachments, $email_id, $object, $email_object = null ) {
// Use get_stylesheet_directory() for a child theme
// Use get_template_directory() for a parent theme
$path_1 = get_template_directory() . '/my-file-1.pdf';
$path_2 = get_template_directory() . '/my-file-2.pdf';
$path_3 = get_template_directory() . '/my-file-3.pdf';
// Customer new account email
if ( isset( $email_id ) && $email_id === 'customer_new_account' ) {
// Get user role(s)
$roles = (array) $object->roles;
// Seller
if ( in_array( 'seller', $roles ) ) {
$attachments[] = $path_1;
$attachments[] = $path_3;
// Customer
} elseif ( in_array( 'customer', $roles ) ) {
$attachments[] = $path_2;
$attachments[] = $path_3;
}
}
return $attachments;
}
add_filter( 'woocommerce_email_attachments', 'filter_woocommerce_email_attachments', 10, 4 );
Code goes in functions.php file of your active theme. Tested in WooCommerce 5.0.0

Related

Generate HTML file from Gravity Form Submission

How do I generate an html file (with specific styling) from a Gravity Form submission using PHP? Right now, I'm using Gravity Form with Gravity PDF to generate PDFs, but I also need these pdfs to be generated as html files. I was told that I could use a gf hook called gform_notification. Here is what I have so far:
add_filter( 'gform_notification_30', 'add_attachment_html', 10, 3 ); //target form id 2, change to your form id
function write_html($filename, $entry){
$filename = fopen( 'file_'.'rand(0, 999999)'.'.html', "w");
$text = $entry;
$path = '/public_html/wp-content/uploads/HTML/';
fwrite($path.$filename, $text);
fclose($filename); }
function add_attachment_html( $notification, $form, $entry ) {
//There is no concept of user notifications anymore, so we will need to target notifications based on other criteria,
//such as name or subject
if( $notification['name'] == 'HTML' ) {
//get upload root for WordPress
$upload = wp_upload_dir();
$upload_path = $upload['basedir'];
//add file, use full path , example -- $attachment = "C:\\xampp\\htdocs\\wpdev\\wp-content\\uploads\\test.txt"
$attachment = $upload_path . $filename;
GFCommon::log_debug( __METHOD__ . '(): file to be attached: ' . $attachment );
if ( file_exists( $attachment ) ) {
$notification['attachments'] = rgar( $notification, 'attachments', array() );
$notification['attachments'][] = $attachment;
GFCommon::log_debug( __METHOD__ . '(): file added to attachments list: ' . print_r( $notification['attachments'], 1 ) );
} else {
GFCommon::log_debug( __METHOD__ . '(): not attaching; file does not exist.' );
}
}
//return altered notification object
return $notification;
}
I'm brand new to coding so please bear with me. My biggest issue is generating the new HTML file. I think I can figure out how to attach it to the notification email (function add_attachment_html) once I get that part done.

wordpress get url of registered script

If I register a script or style (using wp_register_script() or wp_register_style()), is there a way I can get the URL of that script/style?
(If you must know why, I'm trying to put those URL's into another function that generates prefetch link tags so I can prefetch certain scripts/styles for a performance boost in my site.)
Just in case someone is still looking for this:
<?php
function invdr_get_script_uri_by_handler( $handler ){
//Get an instance of WP_Scripts or create new;
$wp_scripts = wp_scripts();
//Get the script by registered handler name
$script = $wp_scripts->registered[ $handler ];
if ( file_exists( ABSPATH . $script->src ) ){
return ABSPATH . $script->src;
}
return false;
}
add_action( 'wp_enqueue_scripts', 'invdr_get_script_uri_by_handler', PHP_INT_MAX );
Tested in wordpress 5.0
You can use wp_scripts() to get the instance of the WP_Scripts class which contains the registered scripts (this class extends WP_Dependencies).
Basically, try looking in:
$wp_scripts = wp_scripts();
var_dump( $wp_scripts->registered );
var_dump( $wp_scripts );
Here's how I've accomplished this in a self-authored plugin to help me enhance dependencies within WordPress:
// Convert relative URL to absolute?
$absolute = true;
$handle = 'your_stylesheet_handle';
$helper = wp_styles();
$object = $helper->registered[ $handle ];
$src = $object->src;
if (
$absolute
&& $helper->in_default_dir( $src )
) {
$src = $helper->base_url . $src;
}
$ver = $object->ver;
if ( ! is_null( $ver ) && empty( $ver ) ) {
$ver = $helper->default_version;
}
if ( isset( $helper->args[ $handle ] ) ) {
$ver = $ver ? $ver . '&' : '';
$ver .= $helper->args[ $handle ];
}
$src = add_query_arg( 'ver', $ver, $src );
$stylesheet_url = urldecode_deep( $src );
Note that the absolute URL conversion is directed towards handling assets registered by WordPress core, as they're typically relative URLs.

Wordpress - upload files and rename with custom user meta

when my users upload a file, I need to rename it using a specific user_meta value. So, using wp_handle_upload I've set a callback function for $upload_overrides like this:
$upload_overrides = array( 'test_form' => false, 'unique_filename_callback' => 'change_document_name' );
and my callback function is
function change_document_name($dir, $name, $ext){
global $current_user;
$doc_type = get_user_meta($current_user->ID, 'document_type', true);
return $doc_type . '_mydoc' . $ext;
}
Now as you can see, we are talking about users documents so I need to rename them according to the document type they've uploaded. For example, if they've uploaded a "passport" and selected the document type (of course), I should get the user_meta 'document_type', use it as prefix and place it in front of the filename uploaded, outputting something like
passport_mydoc.pdf
Of course my function doesn't work and I don't understand why it doesn't take the global $current_user or at least if there is some other method to accomplish this.
Many thanks.
EDIT
To explain it better, my fault, the function change_document_name() does rename the file like so:
_mydoc.ext (e.g _mydoc.pdf)
This means that the function is correctly called and runs, except for the first part ignoring $doc_type variable. For this reason I suppose that the $current_user it's not working. My complete code to upload the file is the following:
if(!empty($_FILES['docfile'])):
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
$upload_overrides = array( 'test_form' => false, 'unique_filename_callback' => 'change_document_name' );
add_filter('upload_dir', 'my_user_folder'); //A documents custom folder
$uploaded_file = wp_handle_upload($_FILES['docfile'], $upload_overrides);
remove_filter( 'upload_dir', 'my_user_folder' );
$doc_file_loc = $uploaded_file['file'];
$doc_file_title = $_FILES['docfile']['name'];
$doc_file_arr = wp_check_filetype(basename($_FILES['docfile']['name']));
$doc_file_type = $doc_file_arr['type'];
$doc_file_att = array(
'post_mime_type' => $doc_file_type,
'post_title' => addslashes($doc_file_title),
'post_content' => '',
'post_status' => 'inherit',
'post_parent' => 0,
'post_author' => $uid
);
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
$doc_file_id = wp_insert_attachment( $doc_file_att, $doc_file_loc, 0 );
$doc_file_url = wp_get_attachment_url( $doc_file_id );
update_user_meta($uid,'document_file', $doc_file_url);
endif;
The hook 'unique_filename_callback' is used according to the codex here https://developer.wordpress.org/reference/functions/wp_unique_filename/
I'm not sure why the global isn't returning the user. It should be. But try get_current_user_id() and see if it works:
function change_document_name( $dir, $name, $ext ){
if ( ! is_user_logged_in() ) {
error_log( "User not logged in." );
return;
}
$user_id = get_current_user_id();
// Uncomment to see if there is any value
// var_dump( $user_id );
$doc_type = get_user_meta( $user_id, 'document_type', true );
// Uncomment to see if there is any value
// var_dump( $doc_type );
if ( ! $doc_type ) {
error_log( "There is no doc type set for the current user with id $user_id" );
return;
}
return $doc_type . '_mydoc' . $ext;
}
I have added some var_dumps in there you can use to see what values are being returned, or you can debug if you have xdebug set up. But this should give you what you need. You can also remove the error logging if you don't want to log those errors. They are there so you can check the site logs and see what is in them.

Woocommerce - overriding the template through a plugin

I have a question: is there a way to override WooCommerce's default template through a plugin the same way you'd do it with a theme?
I have this code:
Class WoocommerceOverride {
public function woocommerce_locate_template( $template, $template_name, $template_path ) {
$plugin_path = SPSL_PLUGIN_PATH;
global $woocommerce;
$_template = $template;
if ( ! $template_path ) $template_path = $woocommerce->template_url;
$plugin_path .= '/woocommerce/';
// Look within passed path within the theme - this is priority
$template = locate_template(
array(
$template_path . $template_name,
$template_name
)
);
// Modification: Get the template from this plugin, if it exists
if ( ! $template && file_exists( $plugin_path . $template_name ) )
$template = $plugin_path . $template_name;
// Use default template
if ( ! $template )
$template = $_template;
//echo $template."<br>";
// Return what we found
return $template;
}
}
add_filter( 'woocommerce_locate_template', array('WoocommerceOverride', 'woocommerce_locate_template'), 10, 3 );
The problem with this code is that it works only partially. On some parts it works, on other parts it does not. For example, I can't customize archive-product.php at all. Whatever I write in there, whether code or plain text, I just don't get any results.
I copied the exact same template files from my plugin folder into my theme folder and it works. However, as I need this as a plugin, I can't go the theme route.
Many thanks.
Using filters wc_get_template_part we can override default WooCommerce template part's.
Using filters woocommerce_locate_template we can override default WooCommerce template's.
Try below example code snippet.
<?php
/**
* Override default WooCommerce templates and template parts from plugin.
*
* E.g.
* Override template 'woocommerce/loop/result-count.php' with 'my-plugin/woocommerce/loop/result-count.php'.
* Override template part 'woocommerce/content-product.php' with 'my-plugin/woocommerce/content-product.php'.
*
* Note: We used folder name 'woocommerce' in plugin to override all woocommerce templates and template parts.
* You can change it as per your requirement.
*/
// Override Template Part's.
add_filter( 'wc_get_template_part', 'override_woocommerce_template_part', 10, 3 );
// Override Template's.
add_filter( 'woocommerce_locate_template', 'override_woocommerce_template', 10, 3 );
/**
* Template Part's
*
* #param string $template Default template file path.
* #param string $slug Template file slug.
* #param string $name Template file name.
* #return string Return the template part from plugin.
*/
function override_woocommerce_template_part( $template, $slug, $name ) {
// UNCOMMENT FOR #DEBUGGING
// echo '<pre>';
// echo 'template: ' . $template . '<br/>';
// echo 'slug: ' . $slug . '<br/>';
// echo 'name: ' . $name . '<br/>';
// echo '</pre>';
// Template directory.
// E.g. /wp-content/plugins/my-plugin/woocommerce/
$template_directory = untrailingslashit( plugin_dir_path( __FILE__ ) ) . 'woocommerce/';
if ( $name ) {
$path = $template_directory . "{$slug}-{$name}.php";
} else {
$path = $template_directory . "{$slug}.php";
}
return file_exists( $path ) ? $path : $template;
}
/**
* Template File
*
* #param string $template Default template file path.
* #param string $template_name Template file name.
* #param string $template_path Template file directory file path.
* #return string Return the template file from plugin.
*/
function override_woocommerce_template( $template, $template_name, $template_path ) {
// UNCOMMENT FOR #DEBUGGING
// echo '<pre>';
// echo 'template: ' . $template . '<br/>';
// echo 'template_name: ' . $template_name . '<br/>';
// echo 'template_path: ' . $template_path . '<br/>';
// echo '</pre>';
// Template directory.
// E.g. /wp-content/plugins/my-plugin/woocommerce/
$template_directory = untrailingslashit( plugin_dir_path( __FILE__ ) ) . 'woocommerce/';
$path = $template_directory . $template_name;
return file_exists( $path ) ? $path : $template;
}
Few months ago the i had the same requirements. So searched a bit more on the net and found useful code which helped me(with a little more customization as per my requirements).
For a detailed code with explanation check this and this link. The approach might be different than what you currently using but it results in overriding woocommerce templates in plugin
You should try adding this code before your // Use default template code:
if( $template_name == '{template part name}') {
$template = $plugin_path . $template_name;
}
In my case {template part name} was global/quantity-input.php
You can find out your exact template part names by temporary adding this line to your code:
print_r($template_name);
I know it's a bit late for answer here but maybe it will be useful for someone else. And keep in mind woocommerce_locate_template is depricated. So there is probably more 'up to date' solution somewhere out there.

Enqueueing scripts if a file exists

I work with wordpress on my child theme.
My site is installed into mydomain.xx/install, but runs from mydomain.xx.
My functions.php works and looks like this:
<?php
/* Script in head */
function carica_scripts() {
/* Common scripts */
// insert scripts here, if some
/* Page-based script */
$pageId = get_the_ID();
$pageType = get_post_type();
$myBaseURL = get_stylesheet_directory_uri() . '/js/';
/* Page-type scripts */
if($pageType == "product") {
wp_enqueue_script('CondAll', $myBaseURL . 'CondAll.js', array('jquery'));
wp_enqueue_script('CondShipping', $myBaseURL . 'CondShipping.js', array('jquery'));
}
/* Page-id scripts */
if($pageId == "1") {
wp_enqueue_script('Cond1', $myBaseURL . 'Cond1.js', array('jquery'));
}
if($pageId == "294") {
wp_enqueue_script('Cond294', $myBaseURL . 'Cond294.js', array('jquery'));
}
if($pageId == "318") {
wp_enqueue_script('Cond318', $myBaseURL . 'Cond318.js', array('jquery'));
}
if($pageId == "232") {
wp_enqueue_script('Cond232', $myBaseURL . 'Cond232.js', array('jquery'));
}
/* END of page-based script */
}
add_action( 'wp_enqueue_scripts', 'carica_scripts' );
?>
What I want to achieve is avoiding all the ifs on $pageId, and to auto-enqueue jQuery script CodXXX.js on page id XXX if the relative file exists in the subdirectory /js/ of my child theme.
file_exists() expects an absolute path to a file rather than a URL.
Use get_stylesheet_directory() to get the path you need. Also get_the_ID() shouldn't be used outside of the loop.
Example:
/*
* Enqueue CondXXX.js on page XXX if file CondXXX.js exists
*/
function carica_scripts() {
global $post;
// Check we're on a page.
if ( ! is_page() ) {
return false;
}
// Build the filename to check.
$handle = 'Cond' . $post->ID;
$relpath = '/js/' . $handle . '.js';
// Get path + url to file.
$file_path = get_stylesheet_directory() . $relpath;
$file_url = get_stylesheet_directory_uri() . $relpath;
if ( file_exists( $file_path ) ) {
wp_enqueue_script( $handle, $file_url, array( 'jquery' ) );
}
}
add_action( 'wp_enqueue_scripts', 'carica_scripts' );
The answer given by Nathan Dawson does not work in my case, I had to do some workarounds. I ended up with the following code:
/* Load scripts in head */
function carica_scripts() {
/* Common scripts */
/* END of common scripts */
/* Page-based script */
$pageId = get_the_ID();
$pageType = get_post_type();
$handle = 'Cond' . $pageId;
$file = $handle .'.js';
$relPath = '/js/';
$styleSheet_path = get_stylesheet_directory();
$domain_base = 'mydomain.it/public_html/';
$start_pos = strpos ( $styleSheet_path, $domain_base) + strlen ($domain_base);
$basePath = substr ( $styleSheet_path, $start_pos); // I need everything after 'mydomain.it/public_html/'
$file_path = $basePath. $relPath . $file;
$enqueue_path = get_stylesheet_directory_uri() . $relPath;
$enqueue_file = $enqueue_path . $file;
/* if page-type is ... (product, in this case) */
if($pageType == "product") {
wp_enqueue_script('CondAll', $enqueue_path . 'CondAll.js', array('jquery'));
wp_enqueue_script('CondShipping', $enqueue_path . 'CondShipping.js', array('jquery'));
}
/* If page id is... (1, in this case - because page 1 is not product but I want CondAll here too) */
if($pageId == "1") {
wp_enqueue_script('CondAll', $enqueue_path . 'CondAll.js', array('jquery'));
}
/* auto load script CondXXX.js from subdir js/ if file exists */
if ( file_exists( $file_path ) ) {
wp_enqueue_script( $handle, $enqueue_file, array( 'jquery' ) );
}
/* END of page-based script */
}
add_action( 'wp_enqueue_scripts', 'carica_scripts' );
Now the the scripts load.

Categories