Detect a screen option change in WordPress Admin - wordpress

In WordPress code, how can I detect a screen option change? Ie, in the below image I want to hook when one of the column screen options changes. Is there a specific hook for this?
My usecase:
I need to add a screen option to the 'All Posts' page. If the user has unchecked my screen option then the All Posts table should not display posts that have a certain category. I have pretty much all my code for this usecase working (see below) apart from being able to hook/detect when 'My Custom Screen Option' is changed (ticked on or off). If I can do that I can then update the users meta with this decision.
function add_custom_columns( $columns ) {
$columns['display_xyz'] = __( 'XYZ Posts' );
return $columns;
}
add_filter( 'manage_posts_columns', 'add_custom_columns' );
function set_sortable_columns( $columns ) {
$columns['display_xyz'] = 'display_xyz';
return $columns;
}
add_filter( 'manage_edit-post_sortable_columns', 'set_sortable_columns' );
function sort_all_posts( $query ) {
global $current_screen;
// If on 'All Posts' page.
if ( isset( $current_screen ) && is_admin() && $current_screen->id === 'edit-post' && $query->query_vars['post_type'] === 'post' ) {
$show_xyz_posts = get_user_meta( get_current_user_id(), 'display_xyz' );
if ( ! $show_xyz_posts ) {
// Edit $query to not retrieve posts that have a specific category 'xyz'
}
}
}
add_filter( 'parse_query', 'sort_all_posts' );
// How to detect change of my custom screen option so I can hook the below option??
function on_change_screen_option($option, $value) {
if ( $option === 'display_xyz' ) {
update_user_meta( get_current_user_id(), 'display_xyz', $value );
}
}
add_action( '???', 'on_change_screen_option' );

Related

How to hide a tag from a download page of Easy Digital Downloads

I created a function to redirect all the products with the tag 'ABC' to a different page (for logged-out users only).
is_singular('download') && has_term(array('ABC'), 'download_tag')
The problem is that logged-in users can still access the page and see the 'ABC' tag in the tags list.
What's the function that I can add to the functions.php file that will only hide the ABC tag specifically?
Thank you
You can hook into get_object_terms to filter terms before they are displayed. Here's an example:
function custom_hide_terms( $terms, $object_ids, $taxonomies, $args )
{
if ( !is_admin() ) {
// note that we are filtering by the term slug, not the term name,
// so be careful with "ABC" versus "abc"
$exclude = array( 'ABC' );
// Loop through terms and remove ABC
if ( $terms ) {
foreach ( $terms as $key => $term ) {
if (is_object($term) && in_array( $term->slug, $exclude ) ) {
unset( $terms[$key] );
}
}
}
}
return $terms;
}
add_filter( 'get_object_terms', 'custom_hide_terms', 10, 4 );

Query posts only with featured image inside "pre_get_posts" hook

I am using the hook "pre_get_posts" to query only posts that have featured image in the front page:
add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts( $q ){
if ( $q->is_home() // only target homepage
&& $q->is_main_query() // only target the main query
&& !is_admin() // target front end only
) {
$q->set( 'meta_key', array( '_thumbnail_id' ) );
}
}
It looks like this portion is being ignored.
$q->set( 'meta_key', array( '_thumbnail_id' ) );
Your help is appreciated.
You need to check whether '_thumbnail_id' meta_key exists or not. So let's modify your code like this.
add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts( $q ){
if ( $q->is_home() // only target homepage
&& $q->is_main_query() // only target the main query
&& !is_admin() // target front end only
) {
$meta_query = array(
array(
'key'=>'_thumbnail_id',
'compare'=>'EXISTS',
),
);
$query->set('meta_query',$meta_query);
}
}

Add input field to every item in cart

I am trying to add a new field on my cart.php file.
I actually want to insert a URL field, so user can set a URL for each order item.
I tried to use a code from another post here but I can't get it to work.
The first and the second functions are working but when it comes to the third one, 'woocommerce_get_item_data' the $cart_item['url'] doesn't contain anything even if I add something in the field and I press Update Cart.
$cart_totals[ $cart_item_key ]['url'] from the first function is outputting the right value when the page load.
I don't know what to do now, thanks for any help.
Here is the code
Add the field
cart/cart.php
<td class="product-url">
<?php
$html = sprintf( '<div class="url"><input type="text" name="cart[%s][url]" value="%s" size="4" title="Url" class="input-text url text" /></div>', $cart_item_key, esc_attr( $values['url'] ) );
echo $html;
?>
</td>
functions.php
// get from session your URL variable and add it to item
add_filter('woocommerce_get_cart_item_from_session', 'cart_item_from_session', 99, 3);
function cart_item_from_session( $data, $values, $key ) {
$data['url'] = isset( $values['url'] ) ? $values['url'] : '';
return $data;
}
// this one does the same as woocommerce_update_cart_action() in plugins\woocommerce\woocommerce-functions.php
// but with your URL variable
// this might not be the best way but it works
add_action( 'init', 'update_cart_action', 9);
function update_cart_action() {
global $woocommerce;
if ( ( ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) ) {
$cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : '';
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
if ( isset( $cart_totals[ $cart_item_key ]['url'] ) ) {
$woocommerce->cart->cart_contents[ $cart_item_key ]['url'] = $cart_totals[ $cart_item_key ]['url'];
}
}
}
}
}
// this is in Order summary. It show Url variable under product name. Same place where Variations are shown.
add_filter( 'woocommerce_get_item_data', 'item_data', 10, 2 );
function item_data( $data, $cart_item ) {
if ( isset( $cart_item['url'] ) ) {
$data['url'] = array('name' => 'Url', 'value' => $cart_item['url']);
}
return $data;
}
// this adds Url as meta in Order for item
add_action ('woocommerce_add_order_item_meta', 'add_item_meta', 10, 2);
function add_item_meta( $item_id, $values ) {
woocommerce_add_order_item_meta( $item_id, 'Url', $values['url'] );
}
Add a textarea field to a WooCommerce cart item
First, we just need to add the textarea field. We use the woocommerce_after_cart_item_name hook so our textarea will appear after the product name.
<?php
/**
* Add a text field to each cart item
*/
function prefix_after_cart_item_name( $cart_item, $cart_item_key ) {
$notes = isset( $cart_item['notes'] ) ? $cart_item['notes'] : '';
printf(
'<div><textarea class="%s" id="cart_notes_%s" data-cart-id="%s">%s</textarea></div>',
'prefix-cart-notes',
$cart_item_key,
$cart_item_key,
$notes
);
}
add_action( 'woocommerce_after_cart_item_name', 'prefix_after_cart_item_name', 10, 2 );
/**
* Enqueue our JS file
*/
function prefix_enqueue_scripts() {
wp_register_script( 'prefix-script', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'update-cart-item-ajax.js', array( 'jquery-blockui' ), time(), true );
wp_localize_script(
'prefix-script',
'prefix_vars',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' )
)
);
wp_enqueue_script( 'prefix-script' );
}
add_action( 'wp_enqueue_scripts', 'prefix_enqueue_scripts' );
´´´
At the moment, the user will be able to enter text into the field but the text won’t save. We are going to use some AJAX to save the text.
The code above not only adds the textarea to the cart item, it also enqueues a JavaScript file ready for our AJAX.
It’s assumed that you’re using the code on this page to create a new plugin. If so, you should create a new JS file with the code below and place the file in the root directory of your plugin.
However, if you’ve added the PHP above to your theme functions.php or as a snippet on your site, you’ll need to change the location of the JS file by updating line 21 of the snippet above to identify the location of the JS file.
´´´
(function($){
$(document).ready(function(){
$('.prefix-cart-notes').on('change keyup paste',function(){
$('.cart_totals').block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
var cart_id = $(this).data('cart-id');
$.ajax(
{
type: 'POST',
url: prefix_vars.ajaxurl,
data: {
action: 'prefix_update_cart_notes',
security: $('#woocommerce-cart-nonce').val(),
notes: $('#cart_notes_' + cart_id).val(),
cart_id: cart_id
},
success: function( response ) {
$('.cart_totals').unblock();
}
}
)
});
});
})(jQuery);
´´´
Now, when the user types anything, the contents of the text field get sent back to the server ready to be saved as meta data to the cart item.
´´´
<?php
/**
* Update cart item notes
*/
function prefix_update_cart_notes() {
// Do a nonce check
if( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'woocommerce-cart' ) ) {
wp_send_json( array( 'nonce_fail' => 1 ) );
exit;
}
// Save the notes to the cart meta
$cart = WC()->cart->cart_contents;
$cart_id = $_POST['cart_id'];
$notes = $_POST['notes'];
$cart_item = $cart[$cart_id];
$cart_item['notes'] = $notes;
WC()->cart->cart_contents[$cart_id] = $cart_item;
WC()->cart->set_session();
wp_send_json( array( 'success' => 1 ) );
exit;
}
add_action( 'wp_ajax_prefix_update_cart_notes', 'prefix_update_cart_notes' );
function prefix_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
foreach( $item as $cart_item_key=>$cart_item ) {
if( isset( $cart_item['notes'] ) ) {
$item->add_meta_data( 'notes', $cart_item['notes'], true );
}
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'prefix_checkout_create_order_line_item', 10, 4 );
´´´
The prefix_update_cart_notes function does a security check using the WooCommerce cart nonce then saves the content of the textarea as meta data in the cart item. You can check out this article for more information about updating cart meta for items that have already been added to the cart.
Add the custom text to the order meta
Finally, we want to pass our meta data to the order so that we can use it after the customer has checked out. The prefix_checkout_create_order_line_item function takes care of that, iterating through each item and saving notes when it finds them.
https://pluginrepublic.com/how-to-add-an-input-field-to-woocommerce-cart-items/

Bulk action for custom post types

I am working on a wordpress project and I want to add the bulk action on my custom post.
I have used Custom Post Type UI plugin for custom post and Advanced Custom Fields plugin for custom fields.
Please suggest me any code or plugin to add bulk action for my custom posts.
Thanks,
Aniket.
Since WordPress 4.7 (released December 2016) it is possible to add custom bulk actions without using JavaScript.
//Hooks
add_action( 'current_screen', 'my_bulk_hooks' );
function my_bulk_hooks() {
if( current_user_can( 'administrator' ) ) {
add_filter( 'bulk_actions-edit-post', 'register_my_bulk_actions' );
add_filter( 'handle_bulk_actions-edit-post', 'my_bulk_action_handler', 10, 3 );
add_action( 'admin_notices', 'my_bulk_action_admin_notice' );
}
}
//Register
function register_my_bulk_actions($bulk_actions) {
$bulk_actions['email_to_eric'] = __( 'Email to Eric', 'text_domain');
return $bulk_actions;
}
//Handle
function my_bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
if ( $doaction !== 'email_to_eric' ) {
return $redirect_to;
}
foreach ( $post_ids as $post_id ) {
// Perform action for each post.
}
$redirect_to = add_query_arg( 'bulk_emailed_posts', count( $post_ids ), $redirect_to );
return $redirect_to;
}
//Notices
function my_bulk_action_admin_notice() {
if ( ! empty( $_REQUEST['bulk_emailed_posts'] ) ) {
$emailed_count = intval( $_REQUEST['bulk_emailed_posts'] );
printf( '<div id="message" class="updated fade">' .
_n( 'Emailed %s post to Eric.',
'Emailed %s posts to Eric.',
$emailed_count,
'text_domain'
) . '</div>', $emailed_count );
}
}
Note.1: You must use bulk_actions filters when WP_Screen object is defined.That's why I used current_screen action in line 2.
Note.2: if you want to add bulk action to custom page like woocommerce products page just change screen id in line 5 & 6. Ex:
add_filter( 'bulk_actions-edit-product', 'register_my_bulk_actions' );
add_filter( 'handle_bulk_actions-edit-product', 'my_bulk_action_handler', 10, 3 );
More information :
Using Custom Bulk Actions
https://make.wordpress.org/core/2016/10/04/custom-bulk-actions/
use "register_post_type" of WordPress function, It easier than the additional plugins
Reference: https://codex.wordpress.org/Function_Reference/register_post_type

WordPress SEO plugin only visible to specific user

I am using the Yoast SEO plugin in WordPress and wanted to know if there was a way to make it only visible to one specific user in the db or in the functions.php file? Not a role, an actual user.
I tried an universal solution to simply add "plugin-name" and disable it, but failed.
But, to show WPSEO only to a specific user (ID equals 2), the following works:
add_action( 'plugins_loaded', 'seo_so_25654837' );
function seo_so_25654837()
{
if ( '2' == get_current_user_id() )
return;
remove_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
}
Don't add the code to functions.php, use it as a normal plugin.
The following is also needed to remove the SEO menu from the admin bar:
add_action( 'wp_before_admin_bar_render', 'bar_so_25654837' );
function bar_so_25654837()
{
if ( '2' == get_current_user_id() )
return;
global $wp_admin_bar;
$nodes = $wp_admin_bar->get_nodes();
foreach( $nodes as $node )
{
if( !$node->parent )
{
if( 'wpseo-menu' === $node->id )
$wp_admin_bar->remove_menu( $node->id );
}
}
}
You can hook to pre_current_active_plugins to remove elements from the table before it is displayed. Using get_current_user_id() within the function will let you selectively hide a plugin.
function hide_plugins_by_user( $all_plugins=false ) {
global $wp_list_table;
// if the current user ID is not 1, hide it.
if ( 1 != get_current_user_id() ){
// the active plugins from the table
$plugins = $wp_list_table->items;
// loop through them
foreach ( $plugins as $key => $val ) {
// use the dir + filename of the plugin to hide
if ( $key == 'plugindir/plugin.php' ) {
unset( $wp_list_table->items[$key] );
}
}
}
}
add_action( 'pre_current_active_plugins', 'hide_plugins_by_user' );
This code is working fine (Credits goes to Hislop):
// Returns true if user has specific role
function check_user_role( $role, $user_id = null ) {
if ( is_numeric( $user_id ) )
$user = get_userdata( $user_id );
else
$user = wp_get_current_user();
if ( empty( $user ) )
return false;
return in_array( $role, (array) $user->roles );
}
// Disable WordPress SEO meta box for all roles other than administrator and seo
function wpse_init(){
if( !(check_user_role('seo') || check_user_role('administrator')) ){
// Remove page analysis columns from post lists, also SEO status on post editor
add_filter('wpseo_use_page_analysis', '__return_false');
// Remove Yoast meta boxes
add_action('add_meta_boxes', 'disable_seo_metabox', 100000);
}
}
add_action('init', 'wpse_init');
function disable_seo_metabox(){
remove_meta_box('wpseo_meta', 'post', 'normal');
remove_meta_box('wpseo_meta', 'page', 'normal');
}
Just place it in the functions.php file.
To disable the Yoast for all the users and enable it for just for few or specific, just add the following piece of code to your function.php file.
function remove_wpseo(){
/* if you want to keep it enabled for user with id 2 */
if ( '2' == get_current_user_id() ) {
return;
}
global $wpseo_front;
if(defined($wpseo_front)){
remove_action('wp_head',array($wpseo_front,'head'),1);
}
else {
$wp_thing = WPSEO_Frontend::get_instance();
remove_action('wp_head',array($wp_thing,'head'),1);
}
}
add_action('template_redirect','remove_wpseo');
Reference: https://makersbyte.com/disable-yoast-seo-plugin-specific-page/

Resources