For the last few years I have been developing a custom theme and various plugins that add options to WPBakery Page Builder elements and create new custom elements, etc.
Everything has worked perfectly up to Page Builder v5.7. But then when v6.0.x came out, suddenly every Checkbox option I have added to every element, be it a custom element or one of Page Builder's standard elements, has a problem: As soon as I click the element in the Page Editor to open it's settings, all checkboxes clear and become unticked regardless of their default or saved values.
If I tick a checkbox and save settings, when I view the front end of the site the option has indeed saved and is working as it should be; but when I open the element's settings window again, they all clear.
I have looked at all my code and compared it to other plugin's code and all of WPBakery's documentation, etc, and I can't see a problem anywhere. I thought it might be a bug with Page Builder v6.0.x and I have sent them a support ticket, but they haven't been able to give me an answer. Other people's plugins seem to be working though, along with all of Page Builder's own built-in elements, which leads me to believe that it must be something to do with my code.
Here is an example:
// After VC Init
add_action( 'vc_after_init', 'gd_after_init_actions' );
// ADD OPTIONS TO VISUAL COMPOSER ELEMENTS //
function gd_after_init_actions() {
// ADD FULL WIDTH CHECKBOX TO SINGLE IMAGE ELEMENTS //
$single_image_attributes = array(
'type' => 'checkbox',
'class' => 'full_width_image',
'param_name' => 'full_width_image',
'value' => array('Force Full Width' => true),
'weight' => 1
);
vc_add_param('vc_single_image', $single_image_attributes);
}
This adds a "Force Full Width" checkbox to Page Builder's standard "Single Image" element. The checkbox appears perfectly and if I check it, save and then view the front end of the site, the checkbox does indeed work; the checkbox value has saved and the image is stretched to full width. But then if I go back to the back end and click on the Single Image element to edit it's settings again, the checkbox becomes unchecked and it's saved value is lost.
Similarly, with plugins in which I am adding options with vc_map(), here is a sample:
function vc_before_init_actions(){
// Stop all if VC is not enabled
if ( !defined( 'WPB_VC_VERSION' ) ) {
return;
}
// ELEMENT CLASS //
class vcResponsiveYouTubeVideo extends WPBakeryShortCode {
// ELEMENT INIT //
function __construct() {
add_action( 'init', array( $this, 'vc_youtube_video_mapping' ) );
add_shortcode( 'vc_youtube', array( $this, 'vc_youtube_video_html' ) );
}
// ELEMENT MAPPING //
public function vc_youtube_video_mapping() {
// Map the block with vc_map()
$youtubeIcon = plugins_url('responsive-youtube-icon.png',__FILE__ );
vc_map(
array(
'name' => __('Responsive YouTube Video', 'text-domain'),
'base' => 'vc_youtube',
'category' => __('Custom Elements', 'text-domain'),
'icon' => $youtubeIcon,
'params' => array(
array(
'type' => 'checkbox',
'param_name' => 'lightbox',
'value' => array('Pop up video in lightbox' => true),
'admin_label' => false,
'weight' => 0,
'group' => 'Custom Group'
),
)
)
);
}
[etc...]
}
This is just a snippet of the code and there is much more to it, but this is just the part pertaining to one of the checkbox options that I have in this particular plugin. Just like the previous example, if I check it and save the options, it works, but then if I come back into the element's settings, it clears.
Even checkboxes that are set to be checked by default:
array(
'type' => 'checkbox',
'param_name' => 'branding',
'value' => array('Keep YouTube Branding in Control Bar' => true),
'std' => true,
'admin_label' => false,
'weight' => 0,
'group' => 'Custom Group'
),
This checkbox still clears as soon as I click open the settings window.
I've done a fair bit of testing and it appears this issue exists (so far) only with Checkboxes. All the other inputs I've created, such as textfields, colorpickers, dropdowns, etc, all save fine and retain their values when I re-open the settings window.
Does anyone any have ideas on this?
we found an issue, it caused because we added strict compare for key-value pairs for checkboxes, but in your mapping value is boolean true, however shortcode saves this as string "1" and when edit form is opening then strict compare fails.
For BC we will fix this in our next release, there is a patch:
Index: include/params/default_params.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- include/params/default_params.php (revision afcb0ccf521c36ce176651964792d18c1f9b1bfc)
+++ include/params/default_params.php (date 1559032145000)
## -85,7 +85,9 ##
$values = isset( $settings['value'] ) && is_array( $settings['value'] ) ? $settings['value'] : array( esc_html__( 'Yes', 'js_composer' ) => 'true' );
if ( ! empty( $values ) ) {
foreach ( $values as $label => $v ) {
- $checked = in_array( $v, $current_value, true ) ? 'checked' : '';
+ // NOTE!! Don't use strict compare here for BC!
+ // #codingStandardsIgnoreLine
+ $checked = in_array( $v, $current_value ) ? 'checked' : '';
$output .= ' <label class="vc_checkbox-label"><input id="' . $settings['param_name'] . '-' . $v . '" value="' . $v . '" class="wpb_vc_param_value ' . $settings['param_name'] . ' ' . $settings['type'] . '" type="checkbox" name="' . $settings['param_name'] . '" ' . $checked . '>' . $label . '</label>';
}
}
Related
I am running a WordPress 5.2.3 site and having trouble with something in the admin panel.
I have a custom role, let's call it librarian, and a custom post type, let's call it book.
I want to make it so that a librarian can edit a book but not create a new one.
Following the advice in another question (WordPress: Disable “Add New” on Custom Post Type) and WordPress documentation, I have ended up with this code:
// Custom post type.
register_post_type('book',
array(
'labels' => array(
'name' => __( 'book' ),
'singular_name' => __( 'Book' )
),
'capability_type' => array('book', 'books'),
'capabilities' => array(
'create_posts' => 'do_not_allow' // <-- The important bit.
),
'map_meta_cap' => true,
'description' => 'Book full of pages',
'exclude_from_search' => true,
'publicly_queryable' => false,
'show_in_nav_menus' => false,
'show_ui' => true,
'show_in_menu' => true,
'show_in_rest' => true,
'menu_icon' => 'dashicons-location',
'menu_position' => 5,
'supports' => array('title', 'revisions')
));
// Custom role.
add_role('librarian', 'Librarian', array(
'read' => true,
'edit_books' => true,
'edit_published_books' => true
));
I was expecting that when I visited edit.php?post_type=book as a librariranthen I would see the list of books for editing, but I would not see the Add New button. However, what I actually get is a 403 response:
Sorry, you are not allowed to access this page.
I think this may be a bug in WordPress, because of the following cases:
If I visit edit.php?post_type=book as an administrator, then I see the list page without the Add New button, as desired.
If I give the librarian role the edit_posts capability, then I see the list page without the Add New button, as desired (but I don't want to give them the edit_posts capability!).
These make me think that it isn't a problem with the custom post type set up in general.
If I remove the 'create_posts' => 'do_not_allow' from the book type registration, the librarian can see the list page, but it includes the Add New button.
This makes me think that it isn't a problem with the custom role set up in general.
Has anyone encountered this issue before? Have I missed anything from my configuration? Or is there an easy patch or workaround?
Any help would be appreciated! Thanks.
It appears that this is a bug in WordPress. I have found the source of the problem and a workaround.
Workaround
If you're not interested in the cause, the workaround is to comment out this bit of cosmetic code in wp-admin/includes/menu.php:
https://github.com/WordPress/WordPress/blob/master/wp-admin/includes/menu.php#L168
/*
* If there is only one submenu and it is has same destination as the parent,
* remove the submenu.
*/
if ( ! empty( $submenu[ $data[2] ] ) && 1 == count( $submenu[ $data[2] ] ) ) {
$subs = $submenu[ $data[2] ];
$first_sub = reset( $subs );
if ( $data[2] == $first_sub[2] ) {
unset( $submenu[ $data[2] ] );
}
}
This will mean that some menu items that previously didn't show a submenu now will (with a single item the same as the main menu item), but that is only a cosmetic UI change.
Cause
For those of you that want to know the detail…
Accessing edit.php?post_type=book was failing this check in wp-admin/includes/menu.php:
https://github.com/WordPress/WordPress/blob/master/wp-admin/includes/menu.php#L341
if ( ! user_can_access_admin_page() ) {
/**
* Fires when access to an admin page is denied.
*
* #since 2.5.0
*/
do_action( 'admin_page_access_denied' );
wp_die( __( 'Sorry, you are not allowed to access this page.' ), 403 );
}
The call to user_can_access_admin_page() calls through to get_admin_page_parent().
If the submenu has been removed, get_admin_page_parent() returns an empty parent which ultimately causes user_can_access_admin_page() to erroneously return false in the case of the librarian role (the administrator role passes for a different reason).
If the submenu is left in place, get_admin_page_parent() returns a non-empty parent and the access check proceeds correctly from there.
So the root issue is that the global $submenu is being used to both determine the UI and also to make decisions on the permissions hierarchy. I don't see an immediate quick fix for this problem that wouldn't have side effects elsewhere throughout the WordPress code, other than the workaround above.
I think I've found a workaround for this without having to edit the core files.
As you said, the cause of this bug is that a empty menu that has no sub-menu items will cause access check to erroneously return false.
So the workaround is to not make the list page a top-level menu. Instead, make it a sub-menu under an existing menu. This way there won't be an empty top-level menu and you can see the list page correctly without the 'Add New' button.
This is only a workaround, not ideal. But perhaps it's better than editing the core files.
The way to create a custom post type while putting its list page as a sub-menu item is simple. The args of register_post_type has an arg called show_in_menu. As the docs say:
If a string of an existing top level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post type will be placed as a sub-menu of that.
So the code will be:
register_post_type('book',
array(
'labels' => array(
'name' => __( 'book' ),
'singular_name' => __( 'Book' )
),
'capability_type' => array('book', 'books'),
'capabilities' => array(
'create_posts' => 'do_not_allow'
),
'map_meta_cap' => true,
'show_ui' => true,
'show_in_menu' => 'tools.php', //or whatever top-level menu you'd like
//... other args omitted
));
I have found 2 Workarounds for this issue:
First off I find it better to assign a specific capability for the custom_post_type create_posts instead of using do_not_allow
So I use:
...
'capability_type' => 'books',
'capabilities' => array(
'create_posts' => 'add_new_books'
),
'map_meta_cap' => true,
...
This way I can assign Admins or other Managers the add_new_books capability, but don't allow it for other roles.
Option 1:
(Filter the user_has_cap to fake that the user has 'edit_posts' but then remove the Posts Menu Item)
add_filter(
'user_has_cap',
function( $all_caps, $caps ) {
global $typenow, $menu;
if ( is_admin() && ! empty( $typenow ) && stripos( $_SERVER['REQUEST_URI'], 'edit.php' ) && stripos( $_SERVER['REQUEST_URI'], 'post_type=' . $typenow ) && in_array( 'edit_posts', $caps, true ) ) {
// Temporarily assign the user the edit_posts capability
$all_caps['edit_posts'] = true;
// Now Remove any menu items with edit_posts besides the custom post type pages.
if ( ! empty( $menu ) ) {
foreach ( $menu as $menu_key => $menu_item ) {
if ( ! empty( $menu_item[1] ) && ( $menu_item[1] === 'edit_posts' || $menu_item[2] === 'edit.php' ) ) {
remove_menu_page( $menu_item[2] );
}
}
}
}
return $all_caps;
},
10,
2
);
While this works it does add some PHP Notices for undefined indexes.
Option 2:
(Filter the $pagenow variable)
add_action(
'admin_menu',
function () {
global $pagenow, $typenow;
if ( is_admin() && ! empty( $typenow ) && ! empty( $pagenow ) && $pagenow === 'edit.php' && stripos( $_SERVER['REQUEST_URI'], 'edit.php' ) && stripos( $_SERVER['REQUEST_URI'], 'post_type=' . $typenow ) ) {
$pagenow = 'custom_post_type_edit.php';
}
}
);
This works without adding any PHP Notices, but may have unforseen issues as it is changing the $pagenow variable, but only on that page.
So far I am using Option 2 without any issues.
this code is worked for me
/**
* Fix Disable add new cpt post (post-new.php?post_type=) - craete_posts
*/
function disable_create_newpost()
{
global $pagenow, $typenow;
if (is_admin() && !empty($typenow) && !empty($pagenow) && $pagenow === 'edit.php' && stripos($_SERVER['REQUEST_URI'], 'edit.php') && stripos($_SERVER['REQUEST_URI'], 'post_type=' . $typenow)) {
$pagenow = 'edit-' . $typenow . '.php';
}
}
add_action('admin_menu', 'disable_create_newpost');
// END PART
thanks for #ggedde
I looked around here and by search engine, but unfortunately I couldn't find a solution for myself.
So, I now ask assistance with a function that I need to customize for the Contact Form 7 WordPress plugin. The function was from another question.
In a drop-down menu (select) I need two details (workshop name and date) in one option field. Both details come from the same post of a custom post type. The first detail is a post_title, the second is a custom-field from Meta-Box plugin.
The following function works in principle, but it only returns the one or the other detail. Probably the solution is within the foreach construct. But I don't know how it works.
I would be very grateful for support!
[UPDATE 2018-08-12]
After further research, I've found the solution at this post and changed the function accordingly.
The solution should look like this:
<select>
<option value="workshop name – date">workshop name – date</option>
...
</select>
This is the function:
add_filter( 'wpcf7_form_tag', 'dynamic_field_choose_workshop', 10, 2);
function dynamic_field_choose_workshop ( $tag, $unused ) {
if ( $tag['name'] != 'workshop' )
return $tag;
$args = array (
'post_type' => 'workshop',
'post_status' => 'publish',
'orderby' => 'name',
'order' => 'ASC',
'numberposts' => - 1,
);
$custom_posts = get_posts($args);
if ( ! $custom_posts )
return $tag;
foreach ( $custom_posts as $custom_post ) {
$ID = $custom_post->ID;
$tag['values'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
$tag['raw_values'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
$tag['labels'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
}
return $tag;
}
There is CF7 extension that will do this for you. Checkout the Smart Grid-Layout for CF7, it introduces a new tag called dynamic_dropdown. This is is what you want to use. The dynamic_dropdown creates a select field and allows you to populate the field options using either a taxonomy, titles of a post type, or a filter. You want to use the filter option to actually construct the options as per your requirement. The tag popup window is self explanatory, however if you get stuck post a comment below and I'll give you some more tips.
Using the following dynamic_dropdown tag,
[dynamic_select workshop-date-select class:select2 "source:filter"]
it creates a <select name="workshop-date-select"> dropdown field which will be converted into a select2 jquery field on the front end, and its values dynamically created using the following function placed in the functions.php file,
add_filter('cf7sg_dynamic_dropdown_custom_options', 'filter_options',10,3);
function filter_options($options, $field_name, $form_key){
/*first we verify if this is the right field from the right form
in case multiple forms with similar fieldd exiss.
the $form_key is a unique key exposed by the Smart Grid-layout plugin
instead of using form IDs to make forms and code more portable across servers.*/
if($form_key != 'my-form' && $field_name != 'workshop-date-select') return $options;
$options = array();
//load your options programmatically, as $value=>$name pairs.
$args = array (
'post_type' => 'workshop',
'post_status' => 'publish',
'orderby' => 'name',
'order' => 'ASC',
'numberposts' => - 1,
);
$workshops = get_posts( $args );
foreach($workshops as $workshop){
$val = $workshop->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $workshop->ID);
$options[$val]=$val;
}
return $options;
}
this will create the desired dropdown select field in the front end.
NOTE of CAUTION: I would populate the option values as the workshop post ID rather than the same text as the option label. When the form is submitted the value of the post ID can be used to populate the notification email with the desired workshop title and date. This gives more flexibility to expand the reported information in the future.
I am trying to override my default templates from customization section, I am using code to do that, but if I am using it I am unable to assign a template to the edit-page page, Can anyone give an idea how both the customization section and edit-page assign template work. I want to set the template when I am creating a page and after assigning it I want to override.
Consider I have a blog page, I want to assign it archive.php template and ten want to override It from customization section. There is the particular condition where I want it to work.
<?php
/**
* Adds the Customize page to Select template For Pages
*/
add_action( 'wp_footer', 'cur_page_template' );
function cur_page_template(){
var_dump( get_option('current_page_template') );
var_dump( get_page_template() );
exit;
}
function widgetsite_template_override($wp_customize){
$wp_customize->add_panel( 'template_options', array(
'title' => __( 'Template Options', 'widgetsite' ),
'description' => $description, // Include html tags such as <p>.
'priority' => 160, // Mixed with top-level-section hierarchy.
) );
$wp_customize->add_section('theme_template_override', array(
'title' => __('Override Templates', 'widgetsite'),
'panel' => 'template_options',
'description' => '',
'priority' => 120,
));
$templates = get_page_templates();
$cats = array();
$i = 0;
foreach($templates as $template_name => $template_file){
//$cats[$template_name] = $template_name;
if (strpos($template_file,'layouts') !== false) {
$cats[$template_file] = $template_name;
}
}
$wp_customize->add_setting('widgetsite_archive_template');
$wp_customize->add_setting('widgetsite_page_template');
$wp_customize->add_setting('widgetsite_index_template');
$wp_customize->add_setting('widgetsite_post_template');
$wp_customize->add_setting('widgetsite_search_template');
$wp_customize->add_control( 'widgetsite_archive_template', array(
'settings' => 'widgetsite_archive_template',
'label' => 'Override Archive Template:',
'section' => 'theme_template_override',
'type' => 'select',
'choices' => array_merge(array( "archive.php"=>get_option('current_page_template')), $cats)
));
$wp_customize->add_control( 'widgetsite_page_template', array(
'settings' => 'widgetsite_page_template',
'label' => 'Override Page Template:',
'section' => 'theme_template_override',
'type' => 'select',
'choices' => array_merge( array( "page.php" =>get_option('current_page_template')), $cats)
));
$wp_customize->add_control( 'widgetsite_index_template', array(
'settings' => 'widgetsite_index_template',
'label' => 'Override Index Template:',
'section' => 'theme_template_override',
'type' => 'select',
'choices' => array_merge(array( "index.php"=>get_option('current_page_template')), $cats)
));
$wp_customize->add_control( 'widgetsite_post_template', array(
'settings' => 'widgetsite_post_template',
'label' => 'Override Post Template:',
'section' => 'theme_template_override',
'type' => 'select',
'choices' => array_merge(array( "post.php"=>get_option('current_page_template')), $cats)
));
$wp_customize->add_control( 'widgetsite_search_template', array(
'settings' => 'widgetsite_search_template',
'label' => 'Override Search Template:',
'section' => 'theme_template_override',
'type' => 'select',
'choices' => array_merge(array( "search.php"=>get_option('current_page_template')), $cats)
));
}
add_action('customize_register', 'widgetsite_template_override');
$theme_mode_templates['archive.php'] = get_theme_mod("widgetsite_archive_template");
$theme_mode_templates['page.php'] = get_theme_mod("widgetsite_page_template");
$theme_mode_templates['index.php'] = get_theme_mod("widgetsite_index_template");
$theme_mode_templates['post.php'] = get_theme_mod("widgetsite_post_template");
$theme_mode_templates['search.php'] = get_theme_mod("widgetsite_search_template");
function widgetsite_template_redirect($template){
global $wp_query;
global $post;
$cur= basename($template);
if( $cur === 'page.php' && get_theme_mod("widgetsite_page_template")){ //note $cur will never be empty!
$template= get_template_directory() . '/' . get_theme_mod("widgetsite_page_template");// assuming this will return correct template...
//if issues try hardcoding a path to test...
}
if( $cur === 'archive.php' && get_theme_mod("widgetsite_archive_template")){ //note $cur will never be empty!
$template= get_template_directory() . '/' . get_theme_mod("widgetsite_archive_template");// assuming this will return correct template...
//if issues try hardcoding a path to test...
}
if( $cur === 'index.php' && get_theme_mod("widgetsite_index_template")){ //note $cur will never be empty!
$template= get_template_directory() . '/' . get_theme_mod("widgetsite_index_template");// assuming this will return correct template...
//if issues try hardcoding a path to test...
}
if( $cur === 'post.php' && get_theme_mod("widgetsite_post_template")){ //note $cur will never be empty!
$template= get_template_directory() . '/' . get_theme_mod("widgetsite_post_template");// assuming this will return correct template...
//if issues try hardcoding a path to test...
}
if( $cur === 'search.php' && get_theme_mod("widgetsite_search_template")){ //note $cur will never be empty!
$template= get_template_directory() . '/' . get_theme_mod("widgetsite_search_template");// assuming this will return correct template...
//if issues try hardcoding a path to test...
}
return $template;
}
add_filter( 'template_include', 'widgetsite_template_redirect', 99 );
How the choose template box works from post edit screen.
It is important to remember pages are also posts and all meta relating to posts are stored in the post meta table. Page post types differ slightly from the standard post types as they do not follow the single-postname.php template use function. Instead pages save the template file path in the wp_postmeta database table with a key of _wp_page_template.
So one option to change this value is to change it after save post.
function save_template_file( $post_id ) {
if ( 'page' != $post->post_type ) {
return;
}
//insert logic here
$filelocation= 'anywhere.....';
update_post_meta($post_id, '_wp_page_template', $filelocation);
}
add_action('save_post', 'save_template_file', 11 );
Now this is not what you are looking for, but you mentioned you wanted to understand the process, so for pages, wp will reference the template file from post meta and pull this value. So you can change it after saving if it will always follow the same logic (slightly optimized the process). This is the file that shows up in the edit post screen and will always pull the db value unless wp tries to load the template and realizes it does not exist anymore, in which case it reverts to the defaults file in the select box.
The filter template_include is within the function that searches for the correct template for the pages post type (other post types have the filter single_template)
Your use of include here is incorrect. Don't forget a filter will expect a value returned to work correctly in this case $template.
So if we want to change the template for pages....
add_filter('template_include', 'assign_new_template');
function assign_new_template ($template){
//we already have a template name, no need to pull it again..
$cur= basename($template);
if( $cur === 'page.php' && get_theme_mod("widgetsite_page_template")){ //note $cur will never be empty!
$template= get_template_directory() . '/layouts/' . get_theme_mod("widgetsite_page_template");// assuming this will return correct template...
//if issues try hardcoding a path to test...
}
// dont need a else, we will only change the template if our logic is satisfied...
// etc
return $template;
}
Setting the selects
You are missing the value for default so i propose the following mod as i cant see what your setting in get_option('current_page_template') but if there is a correct filename there replace page.php with it.
While you are not setting a default value for your select box, your page will render the 1st value of the select if none are marked selected so it should work the same.
$wp_customize->add_control( 'widgetsite_search_template', array(
'settings' => 'widgetsite_search_template',
'label' => 'Override Search Template:',
'section' => 'theme_template_override',
'type' => 'select',
'choices' => array_merge(array("page.php"=>'default'), $cats)
));
If you resave all the options like above it should be working (it was for me)!
I'm in the process of writing a plugin to display some site information to all logged users of a blog.
The easiest way I've found is to attach the info to the the admin-bar. However I'd like to display more information then will easily fit. I'd like to put the data in an overlayed html box that is displayed when the user mouses-over (or clicks) on the title.
In effect I'd like to recreate the effect of the "howdy" item.
Below is the reverent code from my plugin.
$args = array(
'id' => 'counter',
'title' => $visitor_count . ' Unique visitors and ' . $page_views .' Page views',
'href' => '#',
'aria-haspopup' => 'true',
'meta' => array( 'html' => '
<!-- This should be a pop-up message not a fixed box -->
<div style="width:300px;height:100px;background-color:white;box-shadow: 10px 10px 5px #888888;">
here be html
</div>
')
);
$wp_admin_bar->add_node( $args );
Hopefully this makes some sense to you all.
OK cracked it, but looking at the WP source code. meta['onclick'] is escaped but allows javascript, so that can be used to call a function which shows/hide's the div passed in meta['html'].
i.e. (yes I know it just unhides this, but a function should be easy to add to meta['onclick'], that checks and hide's or unhide's the div)
global $wpdb;
global $SH_SWS_data;
$page_views = $wpdb->get_var( "SELECT COUNT(*) FROM ".$SH_SWS_data->tableName);
$visitor_count = $wpdb->get_var( "SELECT COUNT(DISTINCT ip) FROM ".$SH_SWS_data->tableName);
$args = array(
'id' => 'counter',
'title' => $visitor_count . ' Unique visitors and ' . $page_views .' Page views',
'href' => '#',
'aria-haspopup' => 'true',
'meta' => array( 'html' => '
<div id="SH_SWS_message_box" style="visibility:hidden;" width="200px" height="100px" >
<div id="SH_SWS_Chart">Hi all</div>
</div>
',
'onclick' => 'document.getElementById("SH_SWS_message_box").style.visibility="visible";')
);
$wp_admin_bar->add_node( $args );
I'm developing a social network with Buddypress, I created a RSS plugin to pull the RSS feed from the specified websites.
Everything is working, except when the RSS is posted to the activity stream. When I create the activity content to print a link, I set the link target to "_new" to open it in a new page.
Here's the code:
function wprss_add_to_activity_feed($item, $inserted_ID) {
$permalink = $item->get_permalink();
$title = $item->get_title();
$admin = get_user_by('login', 'admin');
# Generates the link
$activity_action = sprintf( __( '%s published a new RSS link: %s - ', 'buddypress'), bp_core_get_userlink( $admin->ID ), '' . attribute_escape( wprss_limit_rss_title_chars($title) ) . '');
/* Record this in activity streams */
bp_activity_add( array(
'user_id' => $admin->ID,
'item_id' => $inserted_ID,
'action' => $activity_action,
'component' => 'rss',
'primary_link' => $permalink,
'type' => 'activity_update',
'hide_sitewide' => false
));
}
It should come up with something like that:
Test
But it prints like that:
Test
Why is this happening?
The 'target' attribute is probably getting stripped by BuddyPress's implementation of the kses filters. You can whitelist the attribute as follows:
function se16329156_whitelist_target_in_activity_action( $allowedtags ) {
$allowedtags['a']['target'] = array();
return $allowedtags;
}
add_filter( 'bp_activity_allowed_tags', 'se16329156_whitelist_target_in_activity_action' );
This probably won't retroactively fix the issue for existing activity items - it's likely that they had the offending attribute stripped before being stored in the database. But it should help for future items.