I have two custom plugins that use the WP Logging class. It creates a custom post type called Logs, which (at least in my case) is only visible inside the admin, for example at /wp-admin/edit.php?s&post_status=all&post_type=wp_log.
To make it easier to tell which plugin is creating the logs, I've added a few hooks. Both plugins use them identically. What they do is:
- Add a sortable Type column to the manage posts screen, and add the type field (which the WP Logging library adds) to that screen.
- Add a dropdown to the top of the screen (next to the date filter) and allow the posts to be filtered by which type value they use.
Here's the code I'm using:
// add a sortable Type column to the posts admin
add_filter( 'manage_edit-wp_log_columns', array( $this, 'type_column' ), 10, 1 );
add_filter( 'manage_edit-wp_log_sortable_columns', array( $this, 'sortable_columns' ), 10, 1 );
add_action( 'manage_wp_log_posts_custom_column', array( $this, 'type_column_content' ), 10, 2 );
// filter the log posts admin by log type
add_filter( 'parse_query', array( $this, 'posts_filter' ), 10, 1 );
add_action( 'restrict_manage_posts', array( $this, 'restrict_log_posts' ) );
/**
* Add a Type column to the posts admin for this post type
*
* @param array $columns
* @return array $columns
*/
public function type_column( $columns ) {
$columns['type'] = __( 'Type', 'form-processor-mailchimp' );
return $columns;
}
/**
* Make the Type column in the posts admin for this post type sortable
*
* @param array $columns
* @return array $columns
*/
public function sortable_columns( $columns ) {
$columns['type'] = 'type';
return $columns;
}
/**
* Add the content for the Type column in the posts admin for this post type
*
* @param string $column_name
* @param int $post_id
*/
public function type_column_content( $column_name, $post_id ) {
if ( 'type' != $column_name ) {
return;
}
// get wp_log_type
$terms = wp_get_post_terms(
$post_id,
'wp_log_type',
array(
'fields' => 'names',
)
);
if ( is_array( $terms ) ) {
echo esc_attr( $terms[0] );
}
}
/**
* Filter log posts by the taxonomy from the dropdown when a value is present
*
* @param object $query
* @return object $query
*/
public function posts_filter( $query ) {
global $pagenow;
$type = 'wp_log';
$taxonomy = 'wp_log_type';
if ( is_admin() && 'edit.php' === $pagenow ) {
if ( isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) === $type ) {
if ( isset( $_GET[ $taxonomy ] ) && '' !== $_GET[ $taxonomy ] ) {
$query->post_type = $type;
$query->tax_query = array(
array(
'taxonomy' => $taxonomy,
'field' => 'slug',
'terms' => esc_attr( $_GET[ $taxonomy ] ),
),
);
}
}
}
}
/**
* Add a filter form for the log admin so we can filter by wp_log_type taxonomy values
*
* @param object $query
* @return object $query
*/
public function restrict_log_posts() {
$type = 'wp_log';
$taxonomy = 'wp_log_type';
// only add filter to post type you want
if ( isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) === $type ) {
// get wp_log_type
$terms = get_terms(
[
'taxonomy' => $taxonomy,
'hide_empty' => true,
]
);
?>
<select name="wp_log_type">
<option value=""><?php _e( 'All log types ', 'form-processor-mailchimp' ); ?></option>
<?php
$current_log_type = isset( $_GET[ $taxonomy ] ) ? esc_attr( $_GET[ $taxonomy ] ) : '';
foreach ( $terms as $key => $term ) {
printf(
'<option value="%s"%s>%s</option>',
$term->slug,
$term->slug == $current_log_type ? ' selected="selected"' : '',
$term->name
);
}
?>
</select>
<?php
}
}
The code is identical between the two plugins in this case. Of course the problem, if it's enabled in both plugins, is that it duplicates the display.
Is there any way I can check to see if these additions have already been made before making them?
I thought this was worth a try (on all the filters, and using doing_action
on all the actions):
if ( ! doing_filter( 'manage_edit-wp_log_columns' ) ) {
add_filter( 'manage_edit-wp_log_columns', array( $this, 'type_column' ), 10, 1 );
}
But it didn't change anything. Is there anything else I can try on this?
I have two custom plugins that use the WP Logging class. It creates a custom post type called Logs, which (at least in my case) is only visible inside the admin, for example at /wp-admin/edit.php?s&post_status=all&post_type=wp_log.
To make it easier to tell which plugin is creating the logs, I've added a few hooks. Both plugins use them identically. What they do is:
- Add a sortable Type column to the manage posts screen, and add the type field (which the WP Logging library adds) to that screen.
- Add a dropdown to the top of the screen (next to the date filter) and allow the posts to be filtered by which type value they use.
Here's the code I'm using:
// add a sortable Type column to the posts admin
add_filter( 'manage_edit-wp_log_columns', array( $this, 'type_column' ), 10, 1 );
add_filter( 'manage_edit-wp_log_sortable_columns', array( $this, 'sortable_columns' ), 10, 1 );
add_action( 'manage_wp_log_posts_custom_column', array( $this, 'type_column_content' ), 10, 2 );
// filter the log posts admin by log type
add_filter( 'parse_query', array( $this, 'posts_filter' ), 10, 1 );
add_action( 'restrict_manage_posts', array( $this, 'restrict_log_posts' ) );
/**
* Add a Type column to the posts admin for this post type
*
* @param array $columns
* @return array $columns
*/
public function type_column( $columns ) {
$columns['type'] = __( 'Type', 'form-processor-mailchimp' );
return $columns;
}
/**
* Make the Type column in the posts admin for this post type sortable
*
* @param array $columns
* @return array $columns
*/
public function sortable_columns( $columns ) {
$columns['type'] = 'type';
return $columns;
}
/**
* Add the content for the Type column in the posts admin for this post type
*
* @param string $column_name
* @param int $post_id
*/
public function type_column_content( $column_name, $post_id ) {
if ( 'type' != $column_name ) {
return;
}
// get wp_log_type
$terms = wp_get_post_terms(
$post_id,
'wp_log_type',
array(
'fields' => 'names',
)
);
if ( is_array( $terms ) ) {
echo esc_attr( $terms[0] );
}
}
/**
* Filter log posts by the taxonomy from the dropdown when a value is present
*
* @param object $query
* @return object $query
*/
public function posts_filter( $query ) {
global $pagenow;
$type = 'wp_log';
$taxonomy = 'wp_log_type';
if ( is_admin() && 'edit.php' === $pagenow ) {
if ( isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) === $type ) {
if ( isset( $_GET[ $taxonomy ] ) && '' !== $_GET[ $taxonomy ] ) {
$query->post_type = $type;
$query->tax_query = array(
array(
'taxonomy' => $taxonomy,
'field' => 'slug',
'terms' => esc_attr( $_GET[ $taxonomy ] ),
),
);
}
}
}
}
/**
* Add a filter form for the log admin so we can filter by wp_log_type taxonomy values
*
* @param object $query
* @return object $query
*/
public function restrict_log_posts() {
$type = 'wp_log';
$taxonomy = 'wp_log_type';
// only add filter to post type you want
if ( isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) === $type ) {
// get wp_log_type
$terms = get_terms(
[
'taxonomy' => $taxonomy,
'hide_empty' => true,
]
);
?>
<select name="wp_log_type">
<option value=""><?php _e( 'All log types ', 'form-processor-mailchimp' ); ?></option>
<?php
$current_log_type = isset( $_GET[ $taxonomy ] ) ? esc_attr( $_GET[ $taxonomy ] ) : '';
foreach ( $terms as $key => $term ) {
printf(
'<option value="%s"%s>%s</option>',
$term->slug,
$term->slug == $current_log_type ? ' selected="selected"' : '',
$term->name
);
}
?>
</select>
<?php
}
}
The code is identical between the two plugins in this case. Of course the problem, if it's enabled in both plugins, is that it duplicates the display.
Is there any way I can check to see if these additions have already been made before making them?
I thought this was worth a try (on all the filters, and using doing_action
on all the actions):
if ( ! doing_filter( 'manage_edit-wp_log_columns' ) ) {
add_filter( 'manage_edit-wp_log_columns', array( $this, 'type_column' ), 10, 1 );
}
But it didn't change anything. Is there anything else I can try on this?
Share Improve this question asked Aug 28, 2019 at 14:07 Jonathan StegallJonathan Stegall 2692 silver badges13 bronze badges 4 |2 Answers
Reset to default 1In your code, you add the filter like this:
add_action( 'restrict_manage_posts', array( $this, 'restrict_log_posts' ) );
Which adds a function that starts like this:
public function restrict_log_posts() {
$type = 'wp_log';
$taxonomy = 'wp_log_type';
// only add filter to post type you want
if ( isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) === $type ) {
// get wp_log_type
$terms = get_terms(
First, this action passes the post type so it can be simplified by adjusting the add_action
and using the first parameter it passes:
public function restrict_log_posts( $post_type ) {
$type = 'wp_log';
$taxonomy = 'wp_log_type';
// only add filter to post type you want
if ( 'wp_log' === $post_type ) {
// get wp_log_type
$terms = get_terms(
Then we could use did_action
to only run it the first time:
public function restrict_log_posts( $post_type ) {
if ( did_action( 'restrict_manage_posts' ) ) {
return;
}
....
But this might not have the desired effect, and it's crude. Instead, this action doesn't belong in this class at all, and should be a standalone action. Then we can define the function only if it isn't already defined:
if ( !function_exists('restrict_logs_by_type') ) {
add_action( 'restrict_manage_posts', 'restrict_logs_by_type', 10, 1 );
/**
* Add a filter form for the log admin so we can filter by wp_log_type taxonomy values
*
*/
function restrict_logs_by_type( $post_type ) {
$type = 'wp_log';
$taxonomy = 'wp_log_type';
// only add filter to post type you want
if ( $type !== $post_type ) {
return;
}
// get wp_log_type
$terms = get_terms([
'taxonomy' => $taxonomy,
'hide_empty' => true,
]);
if ( is_wp_error( $terms ) || empty( $terms ) ) {
// no terms, or the taxonomy doesn't exist, skip
return;
}
?>
<select name="wp_log_type">
<option value=""><?php esc_html_e( 'All log types ', 'form-processor-mailchimp' ); ?></option>
<?php
$current_log_type = isset( $_GET[ $taxonomy ] ) ? esc_attr( $_GET[ $taxonomy ] ) : '';
foreach ( $terms as $key => $term ) {
printf(
'<option value="%s"%s>%s</option>',
esc_attr( $term->slug ),
selected( $term->slug, $current_log_type, false ),
esc_html( $term->name )
);
}
?>
</select>
<?php
}
}
Note that I made a number of significant improvements:
- I fixed a major security hole by adding escaping to your option tags
- I replaced the ugly ternary operator with the
selected
function provided by WP - I replaced the if check with a
!==
, making it a guard. Now the entire function can be unindented by 1, and is more readable. Additionally both the Cyclomatic and NPath complexity have been reduced - The function is now standalone, there was never any need for it to be part of an object or class
- I renamed the function to describe what it does
- If no terms are found, or the taxonomy doesn't exist, this version skips displaying the dropdown entirely. No sense having a dropdown if the only item is "All". Without this, the log screen would crash if there were no log types or entries
- The entire snippet is wrapped in a
function_exists
call, if the function is loaded by the first plugin, the second plugin won't bother defining and adding it
Now that I've been looking at it, I thought of a possible solution.
// add a filter to check for other plugins that might be filtering the log screen
$are_logs_filtered = apply_filters( 'wp_logging_manage_logs_filtered', false );
add_filter( 'wp_logging_manage_logs_filtered', '__return_true' );
if ( false === $are_logs_filtered ) {
// add a sortable Type column to the posts admin
add_filter( 'manage_edit-wp_log_columns', array( $this, 'type_column' ), 10, 1 );
add_filter( 'manage_edit-wp_log_sortable_columns', array( $this, 'sortable_columns' ), 10, 1 );
add_action( 'manage_wp_log_posts_custom_column', array( $this, 'type_column_content' ), 10, 2 );
// filter the log posts admin by log type
add_filter( 'parse_query', array( $this, 'posts_filter' ), 10, 1 );
add_action( 'restrict_manage_posts', array( $this, 'restrict_log_posts' ) );
}
Adding a wp_logging_manage_logs_filtered
to both plugins, and setting its value to true on both plugins, results in the filtering field, the sorted column, and the content in the column, all only happening once.
I am inclined to think that's the best thing to do, but of course I could be missing something.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745201838a4616371.html
if ( class_exists( 'logging library' ) ) { return; }
. If it's already loaded, then don't load it again. The same goes for your code that adds the filter for the roles. You don't need to load both copies – Tom J Nowell ♦ Commented Aug 28, 2019 at 21:34