Do you want to add the "Schedule" options for sale price in WooCoommerce, when using quick edit?
Here is a code that works with simple products
function style_sale_price_dates_quick_edit() {
?>
<style>
.ls-display-none{
display: none;
}
.ls-schedule:hover{
cursor: pointer;
}
</style>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery(document).on("click",".ls-schedule",function(){
var trid=jQuery(this).closest("tr").attr("id");
jQuery("#"+trid+" div").removeClass("ls-display-none");
jQuery("#"+trid+" .ls-schedule").addClass("ls-display-none");
});
jQuery('#the-list').on('click', '.editinline', function() {
var post_id = jQuery(this).closest('tr').attr('id');
post_id = post_id.replace('post-', '');
var sale_price_dates_start = jQuery('#sale_price_dates_start_' + post_id).text();
var sale_price_dates_end = jQuery('#sale_price_dates_end_' + post_id).text();
jQuery('input[name=\'sale_price_dates_start\']', '.inline-edit-row').val(sale_price_dates_start);
jQuery('input[name=\'sale_price_dates_end\']', '.inline-edit-row').val(sale_price_dates_end);
});
})
</script>
<?php
}
add_action('admin_head', 'style_sale_price_dates_quick_edit');
add_action( 'woocommerce_product_quick_edit_start', 'ls_show_custom_field_quick_edit' );
function ls_show_custom_field_quick_edit() {
global $post;
if ($post->post_type !== 'product') return;
?>
<script>
jQuery(document).ready(function(){
var aaaa='<a hred="javascript:void(0)" class="ls-schedule">Schedule</a><div class="ls-display-none"><label><span class="title">Sale price dates</span><span class="input-text-wrap"><input type="date" name="sale_price_dates_start" class="text" value=""><input type="date" name="sale_price_dates_end" class="text" value=""></span></label><br class="clear" /></div>';
jQuery(".price_fields").append(aaaa);
});
</script>
<?php
}
add_action( 'manage_product_posts_custom_column', 'ls_show_custom_field_quick_edit_data', 9999, 2 );
function ls_show_custom_field_quick_edit_data( $column, $post_id ){
if ( 'name' !== $column ) return;
$product = wc_get_product($post_id);
$sale_start_date = $product->get_date_on_sale_from() ? date("Y-m-d",strtotime($product->get_date_on_sale_from())) : '';
$sale_end_date = $product->get_date_on_sale_to() ? date("Y-m-d",strtotime($product->get_date_on_sale_to())) : '';
echo '<div style="display:none;">Start Date: <span id="sale_price_dates_start_' . $post_id . '">' . esc_html($sale_start_date) . '</span></div><div style="display:none;">End Date: <span id="sale_price_dates_end_' . $post_id . '">' . esc_html($sale_end_date) . '</span></div>';
}
add_action( 'woocommerce_product_quick_edit_save', 'ls_save_custom_field_quick_edit' );
function ls_save_custom_field_quick_edit( $product ) {
//$post_id = $product->get_id();
if (isset($_REQUEST['sale_price_dates_start'])) {
$sale_price_dates_start = sanitize_text_field($_REQUEST['sale_price_dates_start']);
if ($sale_price_dates_start) {
$product->set_date_on_sale_from(strtotime($sale_price_dates_start));
} else {
$product->set_date_on_sale_from('');
}
}
if (isset($_REQUEST['sale_price_dates_end'])) {
$sale_price_dates_end = sanitize_text_field($_REQUEST['sale_price_dates_end']);
if ($sale_price_dates_end) {
$product->set_date_on_sale_to(strtotime($sale_price_dates_end));
} else {
$product->set_date_on_sale_to('');
}
}
$product->save();
}
If you copy and paste from websites/word documents to add post and pages in WordPress, then you maybe have noticed that you are copying HTML when you insert.
Yes, there is a key on both Windows and Mac, that can remove the HTML format, but if you forget this, the mess is already being added, and you have moved on with your page so you totally forgot.
Here is an option to disable all format when you paste in the classic editor.
This is only working on the classic editor at the moment
/**
* Enable paste as text in Classic Editor and remove HTML when inserting
*/
add_filter('tiny_mce_before_init', function ($init) {
$init['paste_as_text'] = true;
return $init;
});
add_filter('wpuf_textarea_editor_args', function ($args) {
$args['tinymce']['plugins'] = 'paste';
$args['tinymce']['paste_as_text'] = true;
return $args;
});
add_action('wp_footer', 'custom_paste_as_text', 9999);
add_action('admin_head', 'custom_paste_as_text', 9999);
function custom_paste_as_text()
{
if (is_user_logged_in() && ((isset($_GET['et_fb']) && $_GET['et_fb'] === '1') || (isset($_GET['page']) && $_GET['page'] === 'et_theme_builder'))) {
?>
<script>
document.addEventListener('DOMContentLoaded', function () {
tinymce.on("AddEditor", function (e) {
setTimeout(function () {
plain_text(e);
}, 300);
setTimeout(function () {
plain_text(e);
}, 1000);
setTimeout(function () {
plain_text(e);
}, 2000);
function plain_text(e) {
try {
if (e.editor.plugins.paste.clipboard.pasteFormat.get() !== 'text') {
e.editor.execCommand("mceTogglePlainTextPaste");
var notificationButton = document.querySelector('.mce-notification button');
if (notificationButton) {
notificationButton.click();
}
}
} catch (exception) {
// Prevent JS error originating from execCommand above when tinymce does not have NotificationManager
}
}
});
});
</script>
<?php
}
}
Pretty simply script in HTML, CSS and JS
There is no cookie check, so this appear on all webpages if inserted in a header.php file, or if this is simply being injected to all pages. So beware of that.
Here is the full code if you just want to use inline CSS and inline JS and quick resolve
<div class="overlay" id="popup">
<div class="popup-content">
<h2>Servicemeddelelse</h2>
<p>mail.abusiness.dk er utilgængelig fra 22:00 og estimeret 2 timer frem i dag den 25 januar 2024. <br />Vi beklager de gener det måtte medføre.</p>
<button class="btn btn-primary" onclick="closePopup()">Luk</button>
</div>
</div>
<style>
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.popup-content p {
color: black;
font-size: 19px;
}
.popup-content {
background: #fff;
padding: 20px;
text-align: center;
}
.buttonclass {
background: #3498db;
color: #fff;
border: none;
padding: 10px 20px;
cursor: pointer;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
const popup = document.getElementById("popup");
popup.style.display = "flex";
});
function closePopup() {
const popup = document.getElementById("popup");
popup.style.display = "none";
}
</script>
This is pretty simply, and a needed thing for me sometimes. Despite I run from a lifeset of not including JS on a website, if I can skip it 🙂 I love performance
But this can't be done on advanced webpages sometimes, so here is a quick code so you can add script fast in theme functions without the need of a plugin
add_action('wp_head','woocommerce_js');
function woocommerce_js()
{ // break out of php ?>
<script>
SCRIPT GOES IN HERE
</script>
<?php } // break back into php
Here is a simply code inspired by: https://wordpress.org/plugins/paste-as-plain-text-by-default/
But this is a modified version more simply, and can fit you theme functions, or in code snippet so you have control over it.
Here is the code
/**
* Enable paste as text in Classic Editor
*/
add_filter('tiny_mce_before_init', function ($init) {
$init['paste_as_text'] = true;
return $init;
});
add_filter('wpuf_textarea_editor_args', function ($args) {
$args['tinymce']['plugins'] = 'paste';
$args['tinymce']['paste_as_text'] = true;
return $args;
});
add_action('wp_footer', 'custom_paste_as_text', 9999);
add_action('admin_head', 'custom_paste_as_text', 9999);
function custom_paste_as_text()
{
if (is_user_logged_in() && ((isset($_GET['et_fb']) && $_GET['et_fb'] === '1') || (isset($_GET['page']) && $_GET['page'] === 'et_theme_builder'))) {
?>
<script>
document.addEventListener('DOMContentLoaded', function () {
tinymce.on("AddEditor", function (e) {
setTimeout(function () {
plain_text(e);
}, 300);
setTimeout(function () {
plain_text(e);
}, 1000);
setTimeout(function () {
plain_text(e);
}, 2000);
function plain_text(e) {
try {
if (e.editor.plugins.paste.clipboard.pasteFormat.get() !== 'text') {
e.editor.execCommand("mceTogglePlainTextPaste");
var notificationButton = document.querySelector('.mce-notification button');
if (notificationButton) {
notificationButton.click();
}
}
} catch (exception) {
// Prevent JS error originating from execCommand above when tinymce does not have NotificationManager
}
}
});
});
</script>
<?php
}
}
Do you want to have a fully customized close button in Off Canvas Navigation using Oxygenbuilder and OxyExtras - then here is a quick guide for that:
See this GIF for an example:
The little white close icon, is made with HTML and a SVG file. Pretty simply.
Here is this HTML:
<a href="#" id="closeOffCanvasButton">
<img src="SOURCE FOR SVG FILE" />
</a>
And then I'm using Oxygenbuilder for creating the Off Canvas Menu, with the OxyExtras extension
So this jQuery is working, if you are using OxyExtras, and creating Mega Menu and Off Canvas Menu.
Note that this jQuery is only doing what the native close button from OxyExtras is doing, but this close button is more controllable - so it's possible to add it where you want.
jQuery(document).ready(function ($) {
// Function to close off-canvas menu
function closeOffCanvas() {
// Hide the off-canvas menu and backdrop
$('#off-canvas-main').removeClass('oxy-off-canvas-toggled');
$('.oxy-offcanvas_backdrop').fadeOut();
// Set aria-expanded attribute to false on the burger trigger button
$('#burger-trigger button').attr('aria-expanded', 'false');
// Enable scrolling on the body
$('body').removeClass('oxy-offcanvas-open off-canvas-toggled toggledoff-canvas-main');
$('html').removeClass('off-canvas-toggled toggledoff-canvas-main');
}
// Add click event listener to the custom close button
$('#closeOffCanvasButton').on('click', function (event) {
event.preventDefault(); // Prevent the link from navigating if needed
closeOffCanvas();
});
// Add click event listener to the burger trigger button
$('#burger-trigger button').on('click', function () {
// Set aria-expanded attribute to true when opening the off-canvas
$(this).attr('aria-expanded', 'true');
});
});
Remember to change toggledoff-canvas-main and #off-canvas-main with the Class and ID from Oxygen. These might be autogenerated so there is a -3453 something at the end.
I have customized every Class and ID in Oxygen, so there is some niceness to it.
If you want to remove the native close button, then this CSS can work:
body.off-canvas-toggled div#burger-trigger {
display: none;
}
Just found some of my old images in some backup. Not that backup has been a number 1 choice from me in the beginning, wonder who at that time...?
But due to the fact that this gave me some nostalgic feeling, i ended up deciding that this should be on my site. So here it is.
Backup
Hmm....
Maybe it was because of backup I thought that in 2007 or something i should never touch a computer again.
Ohh boy I was wrong
Let's not dive to much into that thing about backup, but my girlfriend destroyed my
hard drive (by accident of cause I know now, not at that moment i knew) and after that I went offline for a few years.
On that hard drive there was all my work, and my future work I was planning. All of that was lost.
Anyways. Let's skip all the rest negative stuff, I've moved on.
But there was a lot of things going on in that period. Also some good stuff!!! (The love of my life x2)
So here is there something, just something I have collected.
This was the most important stuff. I remember I was very sad at that time all was lost, but life's continue, haaa?
Maybe some day I will tell about OneSite (A time Before Facebook and Without Facebook)
Mr-Fister.dk
This was my first (or second, or third) website I built when I was a youngster.
It was my first work made from scratch in HTML/CSS and PHP - just in notepad (without syntax highlighting and shiiit!)
Before, it was Microsoft Frontpage and "webbyen" or "123hjemmeside" 🙂
Yes, we have all been there! And sorry for the name "Fister" this was before i knew
It was actually pretty big at that time, and very active.
More than 1500 users registered, and a lots of forum/news comments.
That shit went down dog!
Pages-Online.dk
My first serious business in web development. Together with 2 others here in Denmark.
We got clients, I was 15 years old, and life was just started for me.
But there was something else that was more interesting, just put it that way heh
Our clients was:
At the same time I was also a writer on Tweak.dk and DayofDefeat.dk
and together with some "Online friends" we ended up making cool projects.
Casemodding
Something i made 🙂
I helped at a local school to "case-mod" (decorate) one's computer.
Together with a good friend, just because we were older than the others 🙂
We didn't have a clue, and we were maybe those 16-17 years old.
Had responsibility for a lot of 12 year olds. It was fun, but irresponsible!
Got into an issue with a client today, and found this article to get what I want. But it was not complete for me.
I want to disable payment, disable shipping, disable subtotal, and replace with a text box, if there was more than 5 products in cart. On top of that, I want to do the same just with 2 products in cart, for a custom category. This is done with this PHP snippet, that goes into functions. If you got any issues, please write to me and I will help with the code. It's pretty complex 🙂
Steps:
// Disable payment for flat_rate:4 and adjust based on product category
function disable_payment_for_flat_rate_4($needs_payment) {
// Check if WooCommerce is active
if (class_exists('WooCommerce')) {
// Check if flat_rate:4 is selected as the shipping method
$chosen_shipping_method = WC()->session->get('chosen_shipping_methods');
if (in_array('flat_rate:4', $chosen_shipping_method)) {
// Get the cart contents
$cart_contents = WC()->cart->get_cart_contents_count();
// Set the maximum allowed products
$max_allowed_products = 5;
// Check if there are products in the "bundle" category
$bundle_category_products = false;
foreach (WC()->cart->get_cart() as $cart_item) {
$product_id = $cart_item['product_id'];
$product_categories = get_the_terms($product_id, 'product_cat');
// Check if the product belongs to the "bundle" category
if ($product_categories && is_array($product_categories)) {
foreach ($product_categories as $category) {
if ($category->slug === 'bundle') {
$bundle_category_products = true;
break;
}
}
}
}
// Adjust the maximum allowed products if there are products in the "bundle" category
if ($bundle_category_products) {
$max_allowed_products = 2;
}
// If the cart contains more than the allowed products, disable payment
if ($cart_contents > $max_allowed_products) {
$needs_payment = false;
// Enqueue the custom JavaScript
add_action('wp_footer', 'disable_place_order_button_script');
}
}
}
return $needs_payment;
}
// Hook the function to the 'woocommerce_cart_needs_payment' filter
add_filter('woocommerce_cart_needs_payment', 'disable_payment_for_flat_rate_4', 10, 1);
// Enqueue custom JavaScript to replace "Place Order" button with custom text
function disable_place_order_button_script() {
?>
<script type="text/javascript">
jQuery(document).ready(function($){
// Delay the execution to ensure the "Place Order" button is fully loaded
setTimeout(function(){
// Remove the "Place Order" button and replace it with custom text
$('.form-row.place-order').html('<p>Contact us for more information about purchasing and shipping price for this order.</p>');
}, 1000); // Adjust the delay time as needed
});
</script>
<?php
}
// Enqueue custom CSS to hide label for flat_rate:4 shipping method
function disable_label_for_flat_rate_4_style() {
// Check if flat_rate:4 is selected as the shipping method
$chosen_shipping_method = WC()->session->get('chosen_shipping_methods');
if (in_array('flat_rate:4', $chosen_shipping_method)) {
// Get the cart contents
$cart_contents = WC()->cart->get_cart_contents_count();
// Set the maximum allowed products
$max_allowed_products = 5;
// Check if there are products in the "bundle" category
$bundle_category_products = false;
foreach (WC()->cart->get_cart() as $cart_item) {
$product_id = $cart_item['product_id'];
$product_categories = get_the_terms($product_id, 'product_cat');
// Check if the product belongs to the "bundle" category
if ($product_categories && is_array($product_categories)) {
foreach ($product_categories as $category) {
if ($category->slug === 'bundle') {
$bundle_category_products = true;
break;
}
}
}
}
// Adjust the maximum allowed products if there are products in the "bundle" category
if ($bundle_category_products) {
$max_allowed_products = 2;
}
// If the cart contains more than the allowed products, enqueue the custom CSS
if ($cart_contents > $max_allowed_products) {
?>
<style type="text/css">
table.shop_table.woocommerce-checkout-review-order-table {
display: none;
}
</style>
<?php
}
}
}
// Hook the function to the 'wp_head' action
add_action('wp_head', 'disable_label_for_flat_rate_4_style');
With this code snippet you can attach PDF files to e-mail plain and simply
But that was not good enough for me!
So I added this code with a little help from ChatGPT 🙂
First I wanted this only to fire up when the order is completed in WooCommerce. I did that with 'customer_completed_order' which is a standard WooCommerce Hook
After that I asked if they could make it with multiple PDF files. And also with custom category.
Here is what we ended up with - me and the mighty GPT, after several tries.
Example:
'sanketure' is a product category and sanketur.pdf is the PDF we want to send, if customer is buying something from that category.
And then it continues with 'oesters-safari' and 'svampeture'
add_filter('woocommerce_email_attachments', 'custom_attach_pdf_to_emails', 10, 4);
function custom_attach_pdf_to_emails($attachments, $email_id, $order, $email) {
// Check if the email is customer completed order
if ($email_id === 'customer_completed_order') {
$upload_dir = wp_upload_dir();
// Define the product category slugs and their corresponding PDF files
$category_to_pdf = array(
'sanketure' => 'sanketur.pdf',
'oesters-safari' => 'osterssafari.pdf',
'svampeture' => 'svampetur.pdf',
);
// Get the product categories for the order
$product_categories = array();
foreach ($order->get_items() as $item_id => $item) {
$product_id = $item->get_product_id();
$terms = get_the_terms($product_id, 'product_cat');
if ($terms && !is_wp_error($terms)) {
foreach ($terms as $term) {
$product_categories[] = $term->slug;
}
}
}
// Check if any of the product categories match the desired ones
foreach ($product_categories as $category) {
if (isset($category_to_pdf[$category])) {
// Attach the corresponding PDF file
$attachments[] = $upload_dir['basedir'] . "/2023/12/" . $category_to_pdf[$category];
}
}
}
return $attachments;
}
Is this JavaScript confirmation not good enough for you?
Well. Here is another way of doing it, with a nice feedback function from a Contact Form.
The customer can't cancel the subscription, without they finish submit feedback.
You will need Popup maker plugin for this. Or you can make popup function you own.
Add this code snippet to your favorite code operator, and change 'popup1 popmake-2133' according to your settings
// add_shortcode("cancel_subscription_wpform","handsomebeardedguy_after_my_account2");
function handsomebeardedguy_after_my_account() {
echo '<script>
jQuery(document).ready(function($) {
$("td.subscription-actions a.cancel, table.shop_table.subscription_details a.cancel").after(\'<button class="popup1 popmake-2133" style="display:none">popup</button>\');
$(\'form.wpforms-form\').on(\'wpformsAjaxSubmitSuccess\', (event) => {
window.location.replace($(".popup1").prev().attr("href"));
})
$("td.subscription-actions a.cancel, table.shop_table.subscription_details a.cancel").on("click", function(e) {
e.preventDefault();
$(".popup1").click();
})
})
</script>';
}
function andsomebeardedguy_after_my_account_suspend() {
echo '<script>
jQuery(document).ready(function($) {
$("td.subscription-actions a.suspend, table.shop_table.subscription_details a.suspend").after(\'<button class="popup2 popmake-2133" style="display:none">popup</button>\');
$(\'form.wpforms-form\').on(\'wpformsAjaxSubmitSuccess\', (event) => {
window.location.replace($(".popup2").prev().attr("href"));
})
$("td.subscription-actions a.suspend, table.shop_table.subscription_details a.suspend").on("click", function(e) {
e.preventDefault();
$(".popup2").click();
})
})
</script>';
}
add_action( 'woocommerce_after_my_account', 'handsomebeardedguy_after_my_account' );
add_action( 'woocommerce_subscription_details_after_subscription_table', 'handsomebeardedguy_after_my_account' );
add_action( 'woocommerce_after_my_account', 'handsomebeardedguy_after_my_account_suspend' );
add_action( 'woocommerce_subscription_details_after_subscription_table', 'handsomebeardedguy_after_my_account_suspend' );