Since updating to WordPress 6.7, I’ve noticed that plugins not hosted on www.remarpro.com are not translating correctly and are instead displaying only in English. I’ve tried using load_plugin_textdomain()
with both the init
and plugins_loaded
hooks, but the translations are still not being applied.
load_plugin_textdomain()
function returns true when logged..po
and .mo
files are correctly formatted and placed in the plugin’s languages
directory.Despite this, the translations are still not being applied, and everything falls back to English.
Am I missing something here? Is there a specific issue with WordPress 6.7 and plugin translations for plugins not hosted on www.remarpro.com? What steps can I take to resolve this?
Thank you in advance!
]]>I am running into a problem with WP_Widget that I do not understand. When I use WP_Widget to register a classic (non-block) widget, WordPress does not display a Save button on the Appearance → Widgets backend page. However, when I use wp_register_sidebar_widget() and wp_register_widget_control(), the Save button appears as expected.
Is this the intended behavior? Should WP_Widget be compatible with classic (non-block) widgets, or am I missing something in my implementation?
If this is not expected behavior here are two minimal plugin examples (The plugin’s GUI is a text input. The backend is designed to save a default value). [While I don’t expect someone to debug my code, I thought a pro might be able to scan my “WP_Widget” implementation below and tell me if I have done something wrong in my implementation.]
Using “wp_register_sidebar_widget()” and “wp_register_widget_control()”:
<?php
/*
Plugin Name: AC Your Name Two (Without WP_Widget)
Description: A simple widget plugin that displays a text prompt and input field for "Your name".
Version: 1.0
Author: Your Name
*/
/**
* Function to display the front-end of the widget
*/
function ac_your_name_two_widget_display($args) {
// Retrieve the saved options
$options = get_option('ac_your_name_two_options');
$default_name = !empty($options['default_name']) ? $options['default_name'] : __('Your name', 'text_domain');
echo $args['before_widget'];
?>
<div class="ac-your-name-two-widget">
<p><?php echo esc_html__('Your name:', 'text_domain'); ?></p>
<input type="text" value="<?php echo esc_attr($default_name); ?>" readonly />
</div>
<?php
echo $args['after_widget'];
}
/**
* Function to render the widget control form in the WordPress admin
*/
function ac_your_name_two_widget_control() {
// Retrieve existing options, or set defaults
$options = get_option('ac_your_name_two_options');
if (!$options) {
$options = array('default_name' => '');
}
// Process the form when it's submitted
if ($_POST['ac_your_name_two_submit']) {
$options['default_name'] = sanitize_text_field($_POST['ac_your_name_two_default_name']);
update_option('ac_your_name_two_options', $options);
}
// Render the form
?>
<p>
<label for="ac_your_name_two_default_name"><?php _e('Default Name:', 'text_domain'); ?></label>
<input class="widefat" id="ac_your_name_two_default_name" name="ac_your_name_two_default_name" type="text" value="<?php echo esc_attr($options['default_name']); ?>" />
</p>
<input type="hidden" id="ac_your_name_two_submit" name="ac_your_name_two_submit" value="1" />
<?php
}
/**
* Registers the widget and its control
*/
function ac_your_name_two_register() {
// Define widget options for front-end and back-end
$widget_ops = array('classname' => 'ac_your_name_two_widget', 'description' => __('Displays a text input for "Your name".', 'text_domain'));
$control_ops = array('width' => 400, 'height' => 300);
// Register the widget using the older method
wp_register_sidebar_widget('ac_your_name_two_widget', __('AC Your Name Two', 'text_domain'), 'ac_your_name_two_widget_display', $widget_ops);
wp_register_widget_control('ac_your_name_two_widget', __('AC Your Name Two', 'text_domain'), 'ac_your_name_two_widget_control', $control_ops);
}
add_action('widgets_init', 'ac_your_name_two_register');
/**
* Clean up options upon plugin deactivation
*/
function ac_your_name_two_deactivate() {
delete_option('ac_your_name_two_options');
}
register_deactivation_hook(__FILE__, 'ac_your_name_two_deactivate');
Using “WP_Widget (no Save button):
<?php
/*
Plugin Name: AC Your Name Two (WP_Widget)
Description: A widget plugin that displays a text prompt and input field for "Your name" with isolated functions for display and backend.
Version: 1.0
Author: Your Name
*/
/**
* Function to handle front-end display of the widget.
*/
function ac_your_name_two_display_widget($args, $instance) {
$default_name = !empty($instance['default_name']) ? $instance['default_name'] : __('Your name', 'text_domain');
echo $args['before_widget'];
?>
<div class="ac-your-name-two-widget">
<p><?php echo esc_html__('Your name:', 'text_domain'); ?></p>
<input type="text" value="<?php echo esc_attr($default_name); ?>" readonly />
</div>
<?php
echo $args['after_widget'];
}
/**
* Function to handle the back-end form in the widget settings.
*/
function ac_your_name_two_display_form($instance, $widget) {
$default_name = !empty($instance['default_name']) ? $instance['default_name'] : '';
?>
<p>
<label for="<?php echo esc_attr($widget->get_field_id('default_name')); ?>"><?php _e('Default Name:', 'text_domain'); ?></label>
<input class="widefat" id="<?php echo esc_attr($widget->get_field_id('default_name')); ?>" name="<?php echo esc_attr($widget->get_field_name('default_name')); ?>" type="text" value="<?php echo esc_attr($default_name); ?>" />
</p>
<?php
}
/**
* AC Your Name Two Widget Class extending WP_Widget
*/
class AC_Your_Name_Two_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'ac_your_name_two_widget', // Base ID
__('AC Your Name Two', 'text_domain'), // Widget name
array('description' => __('Displays a text input for "Your name".')) // Options
);
}
// Call the isolated front-end display function
public function widget($args, $instance) {
ac_your_name_two_display_widget($args, $instance);
}
// Call the isolated back-end form function
public function form($instance) {
ac_your_name_two_display_form($instance, $this);
}
// Update widget settings
public function update($new_instance, $old_instance) {
$instance = array();
$instance['default_name'] = (!empty($new_instance['default_name'])) ? sanitize_text_field($new_instance['default_name']) : '';
return $instance;
}
}
// Register the widget
function register_ac_your_name_two_widget() {
register_widget('AC_Your_Name_Two_Widget');
}
add_action('widgets_init', 'register_ac_your_name_two_widget');
// Clean up widget data when plugin is deactivated
function ac_your_name_two_deactivate() {
unregister_widget('AC_Your_Name_Two_Widget');
delete_option('widget_ac_your_name_two_widget');
}
register_deactivation_hook(__FILE__, 'ac_your_name_two_deactivate');
]]>I am writing to bring attention to a security vulnerability that I’ve encountered regarding the interaction between Gravity Forms and certain security plugins, particularly in relation to the concealment of the login page URL.
I recently came across an article (link to the article) that highlighted how Gravity Forms interactions can potentially bypass security measures implemented by popular security plugins, leading to the exposure of the hidden login page URL.
The issue arises when a request is made to the Gravity Forms endpoint with a random string appended to the gf_page
parameter. Despite configuring security plugins to hide or customize the login page URL, it was observed that these plugins failed to effectively handle this interaction, thereby revealing the hidden login page URL.
I believe this is a critical security concern as it could allow unauthorized access to the WordPress admin area, circumventing the security measures put in place to protect the site from brute force attacks and other malicious activities.
As a WordPress user/administrator, I am concerned about the implications of this vulnerability and its potential impact on the security of WordPress sites using Gravity Forms and security plugins.
I would like to request the attention of plugin developers and the WordPress community to address this issue and ensure that security plugins are equipped to properly handle interactions with Gravity Forms, thereby enhancing the overall security of WordPress installations.
Any insights, solutions, or recommendations on how to mitigate this vulnerability would be greatly appreciated.
Thank you for your attention to this matter.
]]>i don’t understand what is the message for i have fixed this with two different way . can anyone help me to choose the correct fix.
<div class="'.esc_attr( "kmf-cpr-field ip" ).'">
<p>'.esc_html("Is Public").'</p>
<input type="'.esc_attr( "checkbox" ).'" id="'.esc_attr( "ip" ).'" name="'.esc_attr($this->meta_slug_og.'[ip]').'" '.esc_attr($this->get_the_saved_value(get_the_ID(),$this->meta_slug_og,'select','ip')).'></div>
and another one is
<input type="checkbox" id="editor" name="'.esc_attr($this->meta_slug_og.'[supports][]').'" value="editor" '.esc_attr($this->get_the_saved_value(get_the_ID(),$this->meta_slug_og,'multi_select','supports','editor')).'>
<label for="editor">'.esc_html('Editor').'</label>
it will be kind if anyone can help me with this.
]]>When I submit the form that calls fields directly, it works fine. However, the form that uses do_settings_sections() and callbacks results in a “400 Bad Request” error when submitted.
Why isn’t the do_settings_sections form submitting correctly?
Here’s a simplified version of my code:
function snap_save_settings() {
error_log('triggered snap_save_settings, Success!');
}
add_action('admin_post_snap_save_settings', 'snap_save_settings');
class Snap_Settings extends Snap_Settings_Page {
protected function initialize_settings() {
// General Settings Section
$this->add_section('snap_main_settings', '', [$this, 'main_settings_section_callback'], 'snap-main-settings');
$this->add_field('snap_main_settings', 'snap_linking_mode', '', [$this, 'linking_mode_callback'], 'snap-main-settings');
}
//callback
public function main_settings_section_callback() {
}
public function linking_mode_callback() {
// Output a basic text input form field for testing
echo '<label for="snap_test_input">Test Input:</label>';
echo '<input type="text" id="snap_test_input" name="snap_test_input" value="">';
}
// Display Settings
public function display_settings_page() {
?>
<div class="wrap">
<!-- Form using do_settings_sections() -->
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<label>This form is rendered using do_settings_sections and does not work</label>
<input type="hidden" name="action" value="snap_save_settings">
<?php
settings_fields('snap_settings_group');
do_settings_sections('snap-main-settings');
submit_button();
?>
</form>
<br>
<br>
<!-- Form with fields rendered directly -->
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<label>This form is rendered directly and it works</label>
<input type="hidden" name="action" value="snap_save_settings">
<input type="text" name="snap_test_input" value="Test Value">
<input type="submit" value="Save Changes">
</form>
</div>
<?php
}
}
new Snap_Settings();
Here is the settings base:
abstract class Snap_Settings_Page {
private $sections = [];
abstract protected function initialize_settings();
public function __construct() {
add_action('admin_menu', [$this, 'add_menu_page']);
add_action('admin_init', [$this, 'register_settings']);
}
public function add_menu_page() {
add_options_page(
'Snap Settings', // Page title
'Snap', // Menu title
'manage_options', // Capability
'snap-settings', // Menu slug
[$this, 'display_settings_page'] // Callback function
);
}
public function register_settings() {
$this->initialize_settings();
foreach ($this->sections as $section_id => $section) {
add_settings_section(
$section_id,
$section['title'],
$section['callback'],
$section['page_slug']
);
foreach ($section['fields'] as $field_id => $field) {
add_settings_field(
$field_id,
$field['title'],
$field['callback'],
$field['page_slug'], // Use the page_slug from the field
$section_id
);
register_setting('snap_settings_group', $field_id);
}
}
}
protected function add_section($id, $title, $callback, $page_slug = 'snap-settings') {
$this->sections[$id] = [
'title' => $title,
'callback' => $callback,
'fields' => [],
'page_slug' => $page_slug // Store the page_slug with the section
];
}
protected function add_field($section_id, $field_id, $title, $callback, $page_slug = 'snap-settings') {
if (!isset($this->sections[$section_id])) {
// Optionally handle the error if the section does not exist
return;
}
$this->sections[$section_id]['fields'][$field_id] = [
'title' => $title,
'callback' => $callback,
'page_slug' => $page_slug
];
}
abstract public function display_settings_page();
}
]]>I have a custom block MYPANEL. This custom block works just like a div with a default class and I can put whatever I want inside of it. The point of the custom block MYPANEL is that if later I want to change the HTML of MYPANEL I can do it from the PHP side.
For example, say today MYPANEL is a div with a CSS class that gives it a black border. But in 3 months I decide to redesign MYPANEL and my new design needs a wrapper div to work for some reason, or 3 divs, or I want to use <figure>
instead of div, etc. I want to be able to just change the PHP template instead of having to update every post.
<!-- fallback static HTML generated by javascript -->
<div class="my-panel">
<!-- innerblocks... -->
</div>
<!-- future HTML generated by PHP one day maybe -->
<aside class="my-panel">>
<div class="my-panel_icon" />
<div class="my-panel__inner">
<!-- innerblocks... -->
</div>
</aside>
Right now, on save in javascript, I return a div with the attributes I take from useBlockProps.save and InnerBlocks.Content as child. This saves in the post’s content an unchanging div. So now I need the PHP template to replace that div with whatever HTML I want, while keeping the inner blocks.
I couldn’t find documentation on what the arguments passed to render_callback
?are, but from my debugging I get the block attributes as first argument, some HTML as second argument ($content), and the block instance as the third. I don’t know if the $content is the HTML that was saved from Javascript or HTML generated in PHP that includes dynamic rendering of inner blocks. Either way, there doesn’t seem to be an $innerBlocksHTML argument anywhere. So what’s the appropriate way of getting it?
Should I write a simple regex to remove the outer div from $content? This feels like it could get messy if I ever change the save function in javascript.
Should I iterate the inner blocks and call render_block on every inner block to get their HTML and just concatenate that? Although this probably should work, if $content contains the rendered blocks already, I’m calling all the rendering callbacks of the inner blocks a second time. I think there was an argument called skip_inner_blocks that looked like it made WP skip rendering the $content, but I couldn’t find any documentation on it. Is that what it is for? Is there something like a skip_outer_block setting so I can take just the inner blocks’ content?
What’s the recommended way of doing this?
]]>The goal is to sent a variable that is in my javascript file to my php so that i can store it in the database (currently I only want to echo it out before taking any next step). I created a very simple plugin with help of the wordpress codex and some online tutorials.
However, i keep being unable to get it to work. Every time I sent the AJAX request I get a 500 internal server error and a bad request error.
Can someone help me out with what mistake I’m making in my request and request handling?
// php code
<?php
/*
Plugin Name: ajaxtest
*/
// Enqueue script.js
function simple_ajax_enqueue_script()
{
wp_enqueue_script('ajax-script', plugin_dir_url(__FILE__) . 'script.js', array('jquery'), '1.0', true);
$my_ajax_nonce = wp_create_nonce('ajax_example');
wp_localize_script(
'ajax-script',
'my_ajax_obj',
array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => $my_ajax_nonce,
)
);
}
add_action('wp_enqueue_scripts', 'simple_ajax_enqueue_script');
// Shortcode to display "Hello, world!"
function ajax_test_shortcode()
{
return '<button id="test-ajax-button">Test Ajax</button>';
}
add_shortcode('test', 'ajax_test_shortcode');
/**
* AJAX handler using JSON
*/
add_action('wp_ajax_my_tag_count', 'my_ajax_handler');
add_action("wp_ajax_nopriv_my_tag_count", "my_ajax_handler");
function my_ajax_handler__json()
{
check_ajax_referer('ajax_example');
$datastring = wp_unslash($_POST['sendingdata']);
echo $datastring;
wp_send_json("data was sent successfully");
}
jQuery(document).ready(function ($) {
$('#test-ajax-button').on('click', function (event) {
event.preventDefault();
var datastring = "hello world";
$.post(my_ajax_obj.ajax_url, {
_ajax_nonce: my_ajax_obj.nonce,
action: "my_tag_count",
sendingdata: datastring
}, function (response) {
console.log("Response:", response);
});
});
});
]]>I’m having an issue with a custom block that I created for WordPress. The block is supposed to show up in the “Custom Blocks” category in the block editor, but it’s not appearing when I search for it.
I’ve checked the PHP and JavaScript code for the plugin and everything seems to be correct. I’ve also tried adding some debugging code to see if the functions are being called correctly, but I’m still not able to figure out what’s causing the issue.
Here is the PHP code for the plugin:
<?php
/*
Plugin Name: Related Post Block
Description: Adds a custom block to generate related post code snippets.
*/
// Enqueue the block editor assets
add_action('enqueue_block_editor_assets', 'related_post_block_enqueue_assets');
function related_post_block_enqueue_assets() {
// Enqueue the JavaScript file for the block
wp_enqueue_script(
'related-post-block',
plugins_url('block.js', __FILE__),
array('wp-blocks', 'wp-editor', 'wp-components', 'wp-api-fetch', 'wp-element'), // Add wp-element as a dependency
filemtime(plugin_dir_path(__FILE__) . 'block.js')
);
}
// Register the block category
add_filter('block_categories', 'related_post_block_add_category');
function related_post_block_add_category($categories) {
return array_merge(
$categories,
array(
array(
'slug' => 'custom-blocks',
'title' => 'Custom Blocks',
'icon' => 'admin-generic'
)
)
);
}
And here is the JavaScript code for the block:
(function (blocks, editor, components, apiFetch) {
var el = blocks.element.createElement;
var __ = wp.i18n.__;
blocks.registerBlockType('custom-blocks/related-post', {
title: __('Related Post', 'related-post-block'),
icon: 'admin-links',
category: 'custom-blocks',
keywords: [__('related'), __('post')],
attributes: {
url: {
type: 'string',
source: 'attribute',
attribute: 'data-url',
selector: 'input[type="url"]'
}
},
edit: function (props) {
var attributes = props.attributes;
function updateUrl(event) {
props.setAttributes({ url: event.target.value });
}
return el(
'div',
{},
el(
'input',
{
type: 'url',
placeholder: __('Paste the post URL', 'related-post-block'),
value: attributes.url,
onChange: updateUrl
}
),
el(
editor.InspectorControls,
{},
el(
components.PanelBody,
{ title: __('Options', 'related-post-block'), initialOpen: true },
el(
components.PanelRow,
{},
el(
components.Button,
{
isPrimary: true,
onClick: function () {
var generateUrl = '/wp-json/related-post-block/v1/generate';
apiFetch({ path: generateUrl, method: 'POST', body: attributes.url })
.then(function (response) {
if (response && response.data) {
editor.DomUtils.insertHTML(
document.activeElement,
response.data
);
}
});
}
},
__('Generate', 'related-post-block')
)
)
)
)
);
},
save: function () {
return null; // Save is handled on the server-side
}
});
})(window.wp.blocks, window.wp.editor, window.wp.components, window.wp.apiFetch);
I would really appreciate any help or suggestions on how to resolve this issue. Thank you in advance!
]]>Where I would want it to be is below the add to cart button of the product page. selector: div.summary.entry-summary > form
I could say I am adequately knowledgeable with using Elementor, if this information helps.
]]>