WordPress Plugin Issues - wordpress

I learned how to create a plugin on WordPress a while ago. However, WordPress changed everything around and I'm trying to create the same plugin using the new WordPress format. I've read several things, but tried to jump right in by modifying the WordPress Text Field plugin (one of my goals with redoing the plugin was to make it usable multiple times). I realize the code is really rough, but I'm stuck. I've tried to add two new fields just to see how things go and while they appear when I go to edit the widget once you click save on the Title and first textarea data gets saved, the other two fields dissapear.
I have a feeling I'm missing something obvious, but I just can't seem to figure it out. Here's the code:
'widget_text', 'description' => __('Text or HTML'));
$control_ops = array('width' => 400, 'height' => 350);
$this->WP_Widget('text', __('Multi Excerpt'), $widget_ops, $control_ops);
}
function widget( $args, $instance ) {
extract($args);
$title = apply_filters( 'widget_title', empty($instance['title']) ? '' : $instance['title'], $instance );
$text = apply_filters( 'widget_text', $instance['text'], $instance );
$texta = apply_filters( 'widget_text', $instance['texta'], $instance );
$posts = $instance['posts'];
echo $before_widget;
if ( !empty( $title ) ) { echo $before_title . $title . $after_title; } ?>
'', 'text' => '', 'posts' => '', 'texta' => '' ) );
$title = strip_tags($instance['title']);
$text = format_to_edit($instance['text']);
$texta = format_to_edit($instance['texta']);
$posts = $instance['posts'];
?>
get_field_id('title'); ?>">
get_field_id('title'); ?>" name="get_field_name('title'); ?>" type="text" value="" />
get_field_id('text'); ?>" name="get_field_name('text'); ?>">
get_field_id('texta'); ?>" name="get_field_name('texta'); ?>">
get_field_id('posts'); ?>">Posts:
get_field_id('posts'); ?>" name="get_field_name('posts'); ?>" type="text" value="" />
Thanks in advance.

Edited: I found my original answer was somewhat correct. Below are the details needs to fix your problem.
Change your WP_Widget_Excerpt function to:
function WP_Widget_Excerpt() {
$widget_ops = array('classname' => 'WP_Widget_Excerpt', 'description' => __('Text or HTML'));
$control_ops = array('width' => 400, 'height' => 350);
$this->WP_Widget('WP_Widget_Excerpt', __('Multi Excerpt'), $widget_ops, $control_ops);
}

If your Widget is doing something simple you can use Widgetifyr.com to create your widget for you. I creates the old style widget as well as the new 2.8+ class based widget. This way your widget will run on more versions of Wordpress.

Related

Add different WordPress excerpt formats to different templates

I added the following code to my functions.php file in WordPress 6.1.1 to display excerpts.
function new_excerpt_length($length) {
return 100;
}
add_filter('excerpt_length', 'new_excerpt_length');
function new_excerpt_more($more) {
return '...';
}
add_filter('excerpt_more', 'new_excerpt_more');
...but I also have a use case to show the full excerpt without a read more link.
On page template 1 I add the below code to display the excerpt:
<?php echo the_excerpt(); ?>
...and it displays the excerpt as per the functions.php file but how do I create a 2nd excerpt without the read more link and apply it to page template 2?
Is there a parameter I can use within the_excerpt(parameter); or can I use something like wp_trim_excerpt https://developer.wordpress.org/reference/functions/wp_trim_excerpt/ maybe?
I came across the below code that is supposed to do what I want
function wpex_get_excerpt( $args = array() ) {
// Default arguments.
$defaults = array(
'post' => '',
'length' => 40,
'readmore' => false,
'readmore_text' => esc_html__( 'read more', 'text-domain' ),
'readmore_after' => '',
'custom_excerpts' => true,
'disable_more' => false,
);
// Apply filters to allow child themes mods.
$args = apply_filters( 'wpex_excerpt_defaults', $defaults );
// Parse arguments, takes the function arguments and combines them with the defaults.
$args = wp_parse_args( $args, $defaults );
// Apply filters to allow child themes mods.
$args = apply_filters( 'wpex_excerpt_args', $args );
// Extract arguments to make it easier to use below.
extract( $args );
// Get the current post.
$post = get_post( $post );
// Get the current post id.
$post_id = $post->ID;
// Check for custom excerpts.
if ( $custom_excerpts && has_excerpt( $post_id ) ) {
$output = $post->post_excerpt;
}
// No custom excerpt...so lets generate one.
else {
// Create the readmore link.
$readmore_link = '' . $readmore_text . $readmore_after . '';
// Check for more tag and return content if it exists.
if ( ! $disable_more && strpos( $post->post_content, '<!--more-->' ) ) {
$output = apply_filters( 'the_content', get_the_content( $readmore_text . $readmore_after ) );
}
// No more tag defined so generate excerpt using wp_trim_words.
else {
// Generate an excerpt from the post content.
$output = wp_trim_words( strip_shortcodes( $post->post_content ), $length );
// Add the readmore text to the excerpt if enabled.
if ( $readmore ) {
$output .= apply_filters( 'wpex_readmore_link', $readmore_link );
}
}
}
// Apply filters and return the excerpt.
return apply_filters( 'wpex_excerpt', $output );
}
Output using:
<?php echo wpex_get_excerpt ( $defaults = array(
'length' => 40,
'readmore' => true,
'readmore_text' => esc_html__( 'read more', 'wpex-boutique' ),
'custom_excerpts' => true,
) ); ?>
...but doesn't seem to workas intended. Outputs the excerpt with no link but the args don't see to work when changed. Would be perfect for my use otherwise. Maybe someone sees how to fix this code?
Thanks

custom field value isn't stored in variation_data object

i have following issue with woocommerce/dokan:
I created a custom field for product variation:
custom field in wordpress backend
It works fine, the values are storing and i can change the value at the backend. Therefor i added following lines of code into function.php of theme file:
function variation_settings_fields( $loop, $variation_data, $variation ) {
// Text Field
woocommerce_wp_text_input(
array(
'id' => '_text_field[' . $variation->ID . ']',
'label' => __( 'My Text Field', 'woocommerce' ),
'placeholder' => 'http://',
'desc_tip' => 'true',
'description' => __( 'Enter the custom value here.', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_text_field', true )
)
);
}
/**
* Save new fields for variations
*
*/
function save_variation_settings_fields( $post_id ) {
// Text Field
$text_field = $_POST['_text_field'][ $post_id ];
if( ! empty( $text_field ) ) {
update_post_meta( $post_id, '_text_field', esc_attr( $text_field ) );
}
}
// Add New Variation Settings
add_filter( 'woocommerce_available_variation', 'load_variation_settings_fields' );
/**
* Add custom fields for variations
*
*/
function load_variation_settings_fields( $variations ) {
// duplicate the line for each field
$variations['text_field'] = get_post_meta( $variations[ 'variation_id' ], '_text_field', true );
return $variations;
}
So far, so good. I can set a value and the value can be saved over the backend.
Now i want to change the custom field for this product variation in dokan vendor dashboard. I duplicated html-product-variation.php file into child theme and added the new field:
dokan vendor dashboard product variation
with following code:
<div>
<p class="dokan-form-group">
<label><?php esc_html_e( 'Custom Textfield', 'dokan' ); ?></label>
<textarea class="dokan-form-control" name="_text_field[<?php echo esc_attr( $loop ); ?>]" rows="3" style="width:100%;"><?php echo isset( $variation_data['_text_field'] ) ? esc_textarea( $variation_data['_text_field'] ) : ''; ?></textarea>
</p>
</div>
The problem is, that the value, which i set in the backend isn't shown and if i inspect the variation_data object there is no key in the array which says "_text_field". How can i store/update variation_data object?
I hope it's understandable which issue i'm facing here and look forward to some help :)
Best wishes,
Florian

Wordpress plugin add_settings_field exact code works in one instance but not in a second instance?

I am writing a plugin making admin options pages using the combo "register_setting", "add_settings_section", "add_settings_field". I have a parent menu and 2 sub-menus. Making admin pages in Wordpress is pretty straight forward... it starts when you make the admin page. Here are my parameters for it. (this is done in OOP)
'parent_slug' => 'Tee_Off',
'page_title' => 'Tee-Off Reports',
'menu_title' => 'Tee-Off Reports',
'capability' => 'manage_options',
'menu_slug' => 'tee_offs_reports',
'callback' => 'path to my template file goes here'; //this is correct in my code
so remember my menu slug "tee_offs_reports" posted above is needed for the next step...
class ClubHouseReports
{
function register()
{
add_action( 'admin_init', array( $this, 'teeoff_report_sellector') );
}
function teeoff_report_sellector() {
register_setting( 'my_options_group', 'timer_month' );
register_setting( 'my_options_group', 'timer_day' );
register_setting( 'my_options_group', 'timer_year' );
add_settings_section( 'teeoff-club-options', 'Get Monthy Report', array( $this, 'teeoff_month_section'), 'tee_offs_reports');
add_settings_field( 'timer_month', 'Month', array( $this, 'teeoff_month'), 'tee_offs_reports', 'teeoff-club-options');
add_settings_field( 'timer_day', 'Day', array( $this, 'teeoff_day'), 'tee_offs_reports', 'teeoff-club-options');
add_settings_field( 'timer_year', 'Year', array( $this, 'teeoff_year'), 'tee_offs_reports', 'teeoff-club-options');
}
function teeoff_month_section() {
echo '<p>Reports</p>';
}
function teeoff_month() {
$timer_month = esc_attr( get_option( 'timer_month' ) );
echo '<input type="text" class="regular-text" name="timer_month" value="'.$timer_month.'" placeholder="Month" />';
}
function teeoff_day() {
$timer_day = esc_attr( get_option( 'timer_day' ) );
echo '<input type="text" class="regular-text" name="timer_day" value="'.$timer_day.'" placeholder="Day" />';
}
function teeoff_year() {
$timer_year = esc_attr( get_option( 'timer_year' ) );
echo '<input type="text" class="regular-text" name="timer_month" value="'.$timer_year.'" placeholder="Year" />';
}
}
This class above is being call from the root plugin file, just like the one that works. An instance is made then the method "register()" is called.
In my template file I do this.... just like the one that does work.
<?php settings_errors(); ?>
<form method="post" action="options.php">
<?php settings_fields( 'my_options_group' ); ?>
<?php do_settings_sections('teeoff-club-options'); ?>
<?php submit_button(); ?>
</form>
SO my problem is... except for where the values need to change when you repeat the same code, in this case like, you need to assign a new menu slug, a new name for the "register_setting", and making sure it's aiming at the right callback, which I assure you everything is set right... for some reason this wont render.
I get no errors, all I see is the submit button, and if I use it I get a "success" message, so everything is in scope... but nothing is rendering on the "tee_offs_reports" page except for the submit button... which makes sense since it's hard coded there.
All this to say... I went over my code dozens of time to look for the smallest/stupidiest syntax mistake, or anything why this admin area wont work, while the other which uses the exact same structure and logic, works 100%. Do you see anything wrong with this code? Don't mind the big space between code above, that only happened when I pasted it here.... Is there a restriction in wordpress that I don't know of yet? Why is this not working? While a blue print of it works just fine.
OK, now I'm really baffled... I got it to work, but I highly doubt I'm following the codex rules... or am I?????
here is the code that is working 100%
function teeoff_report_sellector() {
register_setting( 'my_options_group', 'timer_month' );
register_setting( 'my_options_group', 'timer_day' );
register_setting( 'my_options_group', 'timer_year' );
add_settings_section('tee-off-reports', 'Get Monthy Report', array( $this, 'teeoff_month_section'), 'tee-off-reports');
add_settings_field('timer_month', 'Month', array( $this, 'teeoff_month'), 'tee-off-reports', 'tee-off-reports');
add_settings_field('timer_day', 'Day', array( $this, 'teeoff_day'), 'tee-off-reports', 'tee-off-reports');
add_settings_field('timer_year', 'Year', array( $this, 'teeoff_year'), 'tee-off-reports', 'tee-off-reports');
}
function teeoff_month_section() {
echo '<p>Reports</p>';
}
function teeoff_month() {
$timer_month = esc_attr( get_option( 'timer_month' ) );
echo '<input type="date" class="regular-text" name="timer_month" value="'.$timer_month.'" placeholder="Month" />';
}
function teeoff_day() {
$timer_day = esc_attr( get_option( 'timer_day' ) );
echo '<input type="text" class="regular-text" name="timer_day" value="'.$timer_day.'" placeholder="Day" />';
}
function teeoff_year() {
$timer_year = esc_attr( get_option( 'timer_year' ) );
echo '<input type="text" class="regular-text" name="timer_year" value="'.$timer_year.'" placeholder="Year" />';
}
What I did is... instead of using the menu slug like the codex tells you to do, ...(and the first admin page I created works well that way) I replaced that by the "add_settings_section" ID... so if you look at the before last parameter for each "add_settings_field" they are now assigned the ID of the section, codex is supposed to be looking for the menu slug... I always thought anyways... again the first one I did, works awesome that way... so the 2 last parameters of the "add_settings_field" are the same. Weird! Nowhere is the page slug mention in the code above, yet this works 100% and does not break any other code.
Now I'm wondering... did I find a bug in the Settings API? that will be fixed later on, and my plugin is going to stop working? Or did I stumble on the solution by being desperate trying a whole bunch of stuff???
I don't get it... if there's a real WordPress guru out there that can explain this to me I would be very appreciative!

Wordpress: get_post_gallery image custom size

I'm trying to display the post gallery manually, however images are resized to the default thumbnail size, which is way too small. I'm developing a theme which I'd like to sell in the future, so I would like to display the images from the gallery at a custom size, ignoring wordpress settings. How can I do that?
Here's my code:
if ( get_post_gallery() ) :
$gallery = get_post_gallery( get_the_ID(), false );
foreach( $gallery['src'] AS $src )
{
?>
<li data-thumb="<?php echo $src; ?>">
<img src="<?php echo $src; ?>" alt="Gallery image" />
</li>
<?php
}
endif;
I already specified my preffered size in my functions.php file like this: add_image_size( 'slider-size', 1200, 680 );.
So how can I display gallery images manually in a specific size?
You could use a filter to act on shortcode_atts_gallery before you call that gallery ...
add_filter('shortcode_atts_gallery','force_large_images',10,3);
function force_large_images($out, $pairs, $atts) {
$out['size'] = 'my_size'; // for example, "large"
return $out;
}
do not forget also to remove that filter if you do not want it any more ..
remove_filter('shortcode_atts_gallery','force_large_images',10,3);
another way would be to perform your own query ...
$args = array( 'post_mime_type' => 'image', 'post_type' => 'attachment', 'post_parent' => $post->ID, 'order' => 'ASC');
$attachments = get_children($args);
foreach( $attachments as $attachment) {
if ( !empty($attachment->guid ) ) {
$img_url = wp_get_attachment_image_src($attachment->ID, 'full'); //change *full* size with your custom size
// and then do something ..
}

How to add custom post type archive to menu

I have been searching for weeks and I still haven't found a proper solution to this problem.
I am writing a Wordpress Theme. I have a custom post type called Works. I would like to add my Works archive to my menu and have it as well as it's posts highlighted when I access them.
I can access my archive and posts on the following links
Works archive: /works/
Works single post: /works/postname/
My solution so fare have been to name my archive-works.php template file with a template name (Work archive). Then create an empty page using that template and adding the page to the menu. This highlights the archive in the menu but not the single posts.
I can easily solve this with a custom link and some javascript but there must be a better and cleaner way.
You can do a simple trick in your functions.php:
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($classes, $item) {
// Get post_type for this post
$post_type = get_query_var('post_type');
// Go to Menus and add a menu class named: {custom-post-type}-menu-item
// This adds a 'current_page_parent' class to the parent menu item
if( in_array( $post_type.'-menu-item', $classes ) )
array_push($classes, 'current_page_parent');
return $classes;
}
In your case, you just have to add a class 'works-menu-item' with that archive menu item by the admin panel;
To add "custom posttype archive link" to menu, please look at the following guide
Open file functions.php , and enter code below
add_action('admin_head-nav-menus.php', 'wpclean_add_metabox_menu_posttype_archive');
function wpclean_add_metabox_menu_posttype_archive() {
add_meta_box('wpclean-metabox-nav-menu-posttype', __('Custom Post Type Archives'), 'wpclean_metabox_menu_posttype_archive', 'nav-menus', 'side', 'default');
}
function wpclean_metabox_menu_posttype_archive() {
$post_types = get_post_types(array('show_in_nav_menus' => true, 'has_archive' => true), 'object');
if ($post_types) :
$items = array();
$loop_index = 999999;
foreach ($post_types as $post_type) {
$item = new stdClass();
$loop_index++;
$item->object_id = $loop_index;
$item->db_id = 0;
$item->object = 'post_type_' . $post_type->query_var;
$item->menu_item_parent = 0;
$item->type = 'custom';
$item->title = $post_type->labels->name;
$item->url = get_post_type_archive_link($post_type->query_var);
$item->target = '';
$item->attr_title = '';
$item->classes = array();
$item->xfn = '';
$items[] = $item;
}
$walker = new Walker_Nav_Menu_Checklist(array());
echo '<div id="posttype-archive" class="posttypediv">';
echo '<div id="tabs-panel-posttype-archive" class="tabs-panel tabs-panel-active">';
echo '<ul id="posttype-archive-checklist" class="categorychecklist form-no-clear">';
echo walk_nav_menu_tree(array_map('wp_setup_nav_menu_item', $items), 0, (object) array('walker' => $walker));
echo '</ul>';
echo '</div>';
echo '</div>';
echo '<p class="button-controls">';
echo '<span class="add-to-menu">';
echo '<input type="submit"' . disabled(1, 0) . ' class="button-secondary submit-add-to-menu right" value="' . __('Add to Menu') . '" name="add-posttype-archive-menu-item" id="submit-posttype-archive" />';
echo '<span class="spinner"></span>';
echo '</span>';
echo '</p>';
endif;
}
Thanks
Thanks to rasmussvanejensen for her/his nice question and thethangtran for the answer, I am still confused why Wordpress has not yet added such a good feature to its code base by default.
By the way I think there is even a better solution than the one provided by thethangtran, as it may break on some situations.
Note 1
According to the Codex, using register_post_type, one can add extra post_types to the installation. There is chance, some one need to change the 'query_var' and thus the provided code will break.
Note 2
In addition, it may not handle the current-menu-item class, which will be used for css customization to show the menu item as active.
Note 3
As another note on the code, there is no need to define the loop_index, item and items variables. they are absolutely useless.
A better solution
So I suggest using this alternative, for those who want a more robust solution to on this:
function prefix_add_metabox_menu_posttype_archive(){
add_meta_box( 'prefix_metabox_menu_posttype_archive', __( 'Archives' ), 'prefix_metabox_menu_posttype_archive', 'nav-menus', 'side', 'default' );
}
add_action( 'admin_head-nav-menus.php', 'prefix_add_metabox_menu_posttype_archive' );
function prefix_metabox_menu_posttype_archive(){
$post_types = get_post_types( array( 'show_in_nav_menus' => true, 'has_archive' => true ), 'object' );
if( $post_types ){
foreach( $post_types as $post_type ){
$post_type->classes = array( $post_type->name );
$post_type->type = $post_type->name;
$post_type->object_id = $post_type->name;
$post_type->title = $post_type->labels->name;
$post_type->object = 'cpt_archive';
}
$walker = new Walker_Nav_Menu_Checklist( array() );?>
<div id="cpt-archive" class="posttypediv">
<div id="tabs-panel-cpt-archive" class="tabs-panel tabs-panel-active">
<ul id="ctp-archive-checklist" class="categorychecklist form-no-clear"><?php
echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $post_types ), 0, (object) array( 'walker' => $walker ) );?>
</ul>
</div>
</div>
<p class="button-controls">
<span class="add-to-menu">
<input type="submit"<?php disabled( $nav_menu_selected_id, 0 ); ?> class="button-secondary submit-add-to-menu" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-ctp-archive-menu-item" id="submit-cpt-archive" />
</span>
</p><?php
}
}
function prefix_cpt_archive_menu_filter( $items, $menu, $args ){
foreach( $items as &$item ){
if( $item->object != 'cpt_archive' ) continue;
$item->url = get_post_type_archive_link( $item->type );
if( get_query_var( 'post_type' ) == $item->type ){
$item->classes []= 'current-menu-item';
$item->current = true;
}
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'prefix_cpt_archive_menu_filter', 10, 3 );
Navigate to Appearance > Menus;
Make sure you have the Works' custom post type selected at Screen Options;
Click on the name of your custom post type to expand it and then click on the ‘View all’ tab;
You will see an option for All Works. Check the box next to it and then click on the Add to Menu button;
Your custom post type archive will now appear as a menu item in the right column;
By default, the label will be "All Works". You can change this by writing something different at the Navigation Label;
Click on the Save Menu button to save your changes.
I found a solution on GitHub and it works out of the box by simply adding it to the functions.php without any walkers or extra classes.
This code solves it by comparing the slug of the current post type
with the navigation items, and adds a class accordingly.
Code on GitHub

Resources