I've used ACF's "Flexible Content" to create a fairly advanced "page builder" where authors can create a "section" (basically just a wrapping element with a CSS class name and ID) and then add all my flexible content (images, wysiwyg etc) to it.
What I'd like to do is hide some fields for non admins. I don't want any old editor to be able to go in and change a section's ID or class names (as it would mess up the layout).
I'm aware of the "Rules" panel in the ACF admin where you can choose to only display a certain field group to one type of user role, but what I want is that same thing but for individual fields.
It doesn't appear to be doable from the admin interface, but I'm wondering if someone knows how it could be done from my functions.php file? Perhaps some filter or action I can hook into and disable certain fields based on the current user's role?
I've attached two screenshots showing what I'd like hidden:
I'd like to hide these choices from the "Add row" menu:
And I'd like these panels to be invisible to non admins:
Edit: While we're at it, I wouldn't mind hiding individual fields from a repeatable too. You'll notice a "Modifiers" field in the first screenshot, that too would be nice to hide from non admins. I guess the solution would be pretty much the same for both problems?
As of ACF 5.0.0 there is an easier way to do this without having to disable the field or output CSS. If you use the acf/prepare_field hook and return false the field will not render.
<?php
function so37111468_hide_field( $field ) {
// hide the field if the current user is not able to save options within the admin
if ( ! current_user_can( 'manage_options' ) ) {
return false;
}
return $field;
}
add_filter( 'acf/prepare_field/key=MYFIELDKEY', 'so37111468_hide_field' );
?>
The documentation for that filter can be found here: https://www.advancedcustomfields.com/resources/acf-prepare_field/
I haven't managed to actually hide the fields, but I have managed to disable them. Unfortunately simply setting them to disabled in the acf/load_field action wasn't enough to remove them from the dropdown menu so I also added some CSS to the admin page to visually hide them at least. This is good enough seeing as the editors of the site won't exactly do their best to break it.
<?php
/**
* Hide some "ACF Section" related custom fields
*/
add_action('acf/load_field', 'sleek_hide_acf_section_fields', 10, 1);
function sleek_hide_acf_section_fields ($field) {
$hide = array('section_name', 'section_modifiers', 'modifiers');
global $current_user;
if ((isset($field['_name']) and in_array($field['_name'], $hide)) and (is_admin() && is_user_logged_in() && !in_array('administrator', $current_user->roles))) {
$field['disabled'] = true;
}
return $field;
}
add_action('admin_head', 'sleek_hide_acf_section_fields_css');
function sleek_hide_acf_section_fields_css () {
$hide = array('section_name', 'section_modifiers', 'modifiers');
global $current_user;
if (is_admin() && is_user_logged_in() && !in_array('administrator', $current_user->roles)) {
echo '<style>';
foreach ($hide as $h) {
echo 'div.acf-fc-popup a[data-layout="' . $h . '"]{display: none}';
}
echo '</style>';
}
}
Related
Trying to change the href="" of my website logo based on specific costumer groups (we do have 5 of them).
Here's to add a new class (ex: retailer-5%) when they log in:
add_filter( 'body_class', 'body_class_user_role' );
function body_class_user_role( $classes ) {
if( is_user_logged_in() ) {
$user = wp_get_current_user();
$roles = $user->roles;
$classes[] = 'user-role-' . $roles[0];
}
return $classes;
}
What I would like to achieve is when user group class is (ex: retailer-5% ) the link on the logo which is pointing to www.mysite.com points to a specific page like www.mysite.com/retailers-landing
Is there a way to achieve this, please? I'm using Uncode theme and Wordpress latest versions.
Tried this answer but did not work. among others. For my case i need to check first of all the costumer group then change the link of the logo.
Any help would be appreciated.
I want to be able to hide or even replace the 'My account' button when users are logged out and I want to be able to hide or replace the 'Registration' button when users are logged in.
How would I go about doing this? I'm still a amateur at WordPress and I'm still learning, this is what I have so far in my nav-menus.php file.
if( is_user_logged_in() ) {
wp_nav_menu( array( 'My Account' => 'logged-users' ) );
} else {
wp_nav_menu( array( 'Registration' => 'not-logged-users' ) );
}
I know this isn't correct.
First, you need to create both menus, go to Appearance » Menus, create the two menus logged-in and logged-out.
After creating the menus, add this code in your theme’s functions.php file or a site-specific plugin:
function my_wp_nav_menu_args( $args = '' ) {
if( is_user_logged_in() ) {
$args['menu'] = 'logged-in'; //This value stands for the actual name you give to the menu when you create it.
} else {
$args['menu'] = 'logged-out';
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
}
That's all.
If you only need to hide them, then I would do this mainly via CSS. WP adds the class logged-in to the body element when there is a logged-in user, so you can use that to format elements inside of body differently.
Add classes to your menu items via the admin backend, like for example hide-when-logged-in and hide-when-not-logged-in.
Then you can use
body.logged-in .hide-when-logged-in,
body:not(logged-in) .hide-when-not-logged-in {
display: none;
}
in your stylesheet to hide those elements under the appropriate condition.
I just gave single-site administrators the right to add brand new users by adding the following code to my custom plugin that deals with user roles:
function mc_admin_users_caps( $caps, $cap, $user_id, $args ){
foreach( $caps as $key => $capability ){
if( $capability != 'do_not_allow' )
continue;
switch( $cap ) {
case 'edit_user':
case 'edit_users':
$caps[$key] = 'edit_users';
break;
case 'delete_user':
case 'delete_users':
$caps[$key] = 'delete_users';
break;
case 'create_users':
$caps[$key] = $cap;
break;
}
}
return $caps; }
add_filter( 'map_meta_cap', 'mc_admin_users_caps', 1, 4 );
remove_all_filters( 'enable_edit_any_user_configuration' );
add_filter( 'enable_edit_any_user_configuration', '__return_true');
Now, when my admin logs in, they can add new users the way I want them to, but I don't want to give them the option to add an existing user. I attached a screenshot to help you see what I'm talking about. Any idea of how I can keep the ability for admins to add new users, but not existing ones?
I just came across the same issue. For future reference:
To hide the "Add Existing Users" form in Network Admin > Users, you can add a filter to your default site functions.php like so
add_filter('show_network_site_users_add_existing_form', false);
However, this won't remove the form from the individual sites. For this, you'll just need to hide the form with CSS as there's no filter available.
Add the following to your default site theme functions.php
add_action('admin_head', 'remove_existing_user_form');
function remove_existing_user_form() {
if (!is_super_admin()) {
echo '<style>
#add-existing-user,
#add-existing-user + p,
#adduser {
display: none;
}
</style>';
}
}
It's not ideal, but it hides the form for all users except super admins and is what I ended up doing.
Trying to achieve something that should be simple, but I've tried 3 approaches with multiple code variations and I just can't make it work. I'm trying to create a button that will appear in place of the "ADD TO CART" button on single product pages when the item is out of stock. Clicking the button will fire a popup contact form.
Is creating an add action in functions the right way to go, or should I replace the normal button with an if statement? I've tried both, so help with coding either would be greatly appreciated.
You can either hook into woocommerce_loop_add_to_cart_args using a filter in your functions.php or edit the template file directly by pulling it into your theme. Either way will require a bit of PHP.
If doing it in your functions.php, it would look something like this (untested but should send you down the right path):
<?php
add_filter( 'woocommerce_loop_add_to_cart_link', 'my_out_of_stock_button' );
function my_out_of_stock_button( $args ){
global $product;
if( $product && !$product->is_in_stock() ){
return 'Contact us';
}
return $args;
}
I don't know what your button code should actually look like or what other information you need to capture, but this is how you could override the "Add to Cart" button and replace it if out of stock.
UPDATE
LoicTheAztec brought up a great point - the filter provided only affects the button on the archive, category, tag overview pages - not the individual product pages. There are no hooks for the individual product page buttons BUT you can copy the templates to your theme and override them.
You'll want to look at the files in templates/single-product/add-to-cart. Use a similar if statement as above:
#simple.php
<?php if ( $product->is_in_stock() ) : ?>
// Standard WooCommerce code
<?php else: ?>
// Your button code
<?php endif; ?>
Just add below code in functions.php file of your enabled theme reference
add_action('woocommerce_after_shop_loop_item', 'themelocation_change_outofstock_to_contact_us', 1);
// for shop page
function themelocation_change_outofstock_to_contact_us() {
global $product;
if (!$product->is_in_stock()) {
remove_action('woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart');
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart');
//change the link to your contact us page
echo ' Contact Us ';
}
}
// for single page
add_filter('woocommerce_get_availability', 'wcs_custom_get_availability', 1, 2);
function wcs_custom_get_availability($availability, $_product) {
// Change In Stock Text
if ($_product->is_in_stock()) {
$availability['availability'] = __('Available!', 'woocommerce');
}
// Change Out of Stock Text
if (!$_product->is_in_stock()) {
$availability['availability'] = __(' Contact Us ', 'woocommerce');
}
return $availability;
}
I was looking for a way to show a contact button on bespoke products and
#ahwychkchih solution works great. One issue I had though is that schema markup will show as out of stock for those products which is not the case for beskpoke products is just they can't be purchased straight away so I've added this to force in_stock markup for my products. I'm aware that this solution would affect all products so you can always add a product id filter if needed
// Force In Stock schema markup
function fix_my_product_offers_schema ($markup_offer, $product) {
if (!$product->is_in_stock()) {
$markup_offer['availability'] = 'https://schema.org/InStock';
}
return $markup_offer;
}
add_filter('woocommerce_structured_data_product_offer', 'fix_my_product_offers_schema', 1, 2);
I am running a wholesale shop on Woocommerce. Login is required to see the prices. This is set up and working properly. Now I wish to add a logon form on every product page to only show to visitors (not logged on users).
I am using the WooCommerce Catalog Visibility plugin. This plugin offers the functionality I described above, but my theme is somehow messing it up. The plugin author says to talk to the theme developer and the theme developer says to talk to the plugin author. So now I am trying to find a workaround.
First issue: The plugin comes with a shortcode [woocommerce_logon_form] that will display a logon form. I don't want to manually add this to every existing product since I have thousands of products on my site. I am looking for a way to get it in through the code for the product page layout.
I found this code (to be added to the functions.php) to work well:
// adds notice at single product page above add to cart
add_action( 'woocommerce_single_product_summary', 'return_policy', 20 );
function return_policy() {
echo '<p id="rtrn">30-day return policy offered. See Terms and Conditions for details.</p>';
}
However, it will only show text. The short code won't work when added instead of the sample text.
Second issue: The short code shows the form even when the customer is already logged in.
I am currently using this nice code that shows or hides content depending on whether the user is logged in or not:
add_shortcode( 'access', 'access_check_shortcode' );
function access_check_shortcode( $attr, $content = null ) {
extract( shortcode_atts( array( 'capability' => 'read' ), $attr ) );
if ( current_user_can( $capability ) && !is_null( $content ) && !is_feed() )
return $content;
return '';
}
add_shortcode( 'visitor', 'visitor_check_shortcode' );
function visitor_check_shortcode( $atts, $content = null ) {
if ( ( !is_user_logged_in() && !is_null( $content ) ) || is_feed() )
return $content;
return '';
}
That shortcode works perfectly for text, but not with other shortcodes.
So the combination of these short codes: [visitor][woocommerce_logon_form][/visitor] will not show the logon form to visitors. Instead it will only show them this as text [woocommerce_logon_form].
Please help! I am sure this is probably easily fixed by someone with coding skills.
I appreciate your effort to answer to this question. Keep in mind that my understanding of code is very limited and it would be great if you can also point out in which file to add or modify code.
To make your shortcode working in php code or in php/html code you need to use a native WordPress function do_shortcode() … You can use it with your shortcode for example in your 1st function this way:
add_action( 'woocommerce_single_product_summary', 'return_policy', 20 );
function return_policy() {
echo do_shortcode('[woocommerce_logon_form]');
}
And this will work…
To see all the different hooks you can use instead of woocommerce_single_product_summary, please see this 2 templates code to chose in case a more convenient hook:
WooCommerce single-product.php template
WooCommerce content-single-product.php template
You can also add it the same way in one of your existing short codes, this way:
add_shortcode( 'visitor', 'visitor_check_shortcode' );
function visitor_check_shortcode( $atts, $content = null ) {
if ( ( !is_user_logged_in() && !is_null( $content ) ) || is_feed() )
return do_shortcode('[woocommerce_logon_form]');
return '';
}
And this will work too.
See as reference this answer: Change markup in WooCommerce shortcode output
So as you can see your problem is solved on both issues