In a plugin I am developing, I need to store payments, IPN and transactions for customers in both frontend and backend. However I am concerned that the admin will use his actions power to delete the transactions or financial data from site which has bad implications.


How can I prevent the admin from deleting payments/financial data in a way that ensures that I'm not trying to restrict admins too much, but also takes customer information and financial data as high priority. I'm not asking what's the better way for me to do it? But rather asking what's the better way for WordPress community (as administration, as a customer) as I am trying to avoid future complaints about the way implemented to do this action.

What I currently have

 * Constructor
public function __construct() {

    // Do not allow payments and transactions to be trashed
    add_action( 'wp_trash_post',                            array( $this, 'disable_trash' ) );
    add_action( 'before_delete_post',                       array( $this, 'disable_trash' ) );

 * Disable trash
public function disable_trash( $post_id ) {
    global $post_type;

    if ( in_array( $post_type, array( 'payment', 'transaction' ) ) ) {
        wp_die( __( 'You are not allowed to trash payments or transactions.', 'xxx' ) );
  • 1
    better is a subjective thing and whatever is better for me will not be better for you. You will have to define "better" in order to be able to get meaningful answer. Personally, I don't like what you are trying to do at all, there is a difference between making absolutely sure that the user understands the implications of deleting such data and actually preventing him from doing that Sep 22, 2016 at 3:02
  • ... but if you are going to do it you have to handle all the relevant GUI as well Sep 22, 2016 at 3:04
  • So you are saying that it would be more user friendly to just warn users about the implications of erasing such data rather than preventing them ? Actually that makes sense Sep 22, 2016 at 3:13
  • Don't know if it is more user friendly, but I just instinctively object to taking power from admins. admins should be able to admin their sites. Sep 22, 2016 at 6:04
  • @MarkKaplun On the other hand, when it comes to financial data, it may be mandatory for auditing purposes to rule out tampering by admins. That might be better for the admins themselves as well.
    – cjbj
    Sep 22, 2016 at 9:10

3 Answers 3


Here's another approach using the map_meta_cap filter that's applied within the map_meta_cap() function within the has_cap() method of the WP_User class (PHP 5.4+):

add_filter( 'map_meta_cap', function ( $caps, $cap, $user_id, $args )
    // Nothing to do
    if( 'delete_post' !== $cap || empty( $args[0] ) )
        return $caps;

    // Target the payment and transaction post types
    if( in_array( get_post_type( $args[0] ), [ 'payment', 'transaction' ], true ) )
        $caps[] = 'do_not_allow';       

    return $caps;    
}, 10, 4 );

where we target the delete_post meta capability and the payment and transaction custom post types.

As far as I understand and skimming through the get_post_type_capabilities() function we don't need the map_meta_cap argument set as true, in the register_post_type settings, to target the delete_post meta capability.

ps: Here are some good descriptions of the map_meta_cap filter and helpful examples by Justin Tadlock here and Toscho here. Here I found an old example that I had forgot I wrote, that we could also adjust to avoid trash/delete on some given pages and user roles. Here's an answer by TheDeadMedic that links to an answer by Seamus Leahy regarding register_post_type approach. Here are some more examples on this site. Hope it helps!

  • 1
    if( in_array( get_post_type( $args[0] ), [ 'payment', 'transaction' ], true ) missing a ) at end, other than that works like charm. Sep 22, 2016 at 13:26
  • 1
    ps: The admins of your site might also upload a plugin or change the theme, that can modify the database to their likings. So you should consider that kind of power too and also disable theme/plugin editors. Check e.g. out the DISALLOW_FILE_EDIT and DISALLOW_FILE_MODS constants here. @AhmedMahdi
    – birgire
    Sep 22, 2016 at 13:45

A better way to prevent deletion would be to disable that capability for all roles. When you register your post types 'payment' and 'transaction' also define a capability_type with the same name as your post type. This will give you capabilities read_payment, edit_payment and delete_payment (same for transaction).

You can then deny this capability on roles in this way:

$wp_roles->remove_cap( 'editor', 'delete_payment' );
$wp_roles->remove_cap( 'admin', 'delete_payment' );

Always beware that since admins can edit code on your site, they will still be able to circumvent the deletion, unless you block code editing in the backend and restrict ftp and database access. Also read this discussion on getting all available roles.

  • Yes I am aware that an admin can just remove the entries from phpmyadmin. I'm only trying to do my best to ensure that the frontend/backend provides no way to delete that data. Sep 22, 2016 at 13:19

I used this code in a website , where we can hide edit, trash, view buttons even in bulk edit drop-down,

if(!current_user_can('administrator')) //not an admin
    add_filter( 'post_row_actions', 'remove_row_actions', 10, 1 );
    function remove_row_actions( $actions )
        if( get_post_type() === 'post' ) {
            unset( $actions['edit'] );
            unset( $actions['view'] );
            unset( $actions['trash'] );
            unset( $actions['inline hide-if-no-js'] );
        return $actions;

if(!current_user_can('administrator'))//not and admin
    global $pagenow;
    if ( 'post.php' == $pagenow || 'post-new.php' == $pagenow ) {
        add_action( 'admin_head', 'wpse_125800_custom_publish_box' );
        function wpse_125800_custom_publish_box() {
            $style = '';
            $style .= '<style type="text/css">';
            $style .= '#delete-action, .bulkactions';
            $style .= '{display: none; }';
            $style .= '</style>';

            echo $style;
  • 1
    If you simply hide a button with css, the user can unhide it in his browser and do as he pleases.
    – cjbj
    Sep 22, 2016 at 13:16
  • Yes, for bulk action there is a possibility to unhide it and do the actions. We can try this [code] $output = preg_replace('#<div class="bulkactions">(.*?) </div>#', ' ', $incoming_data); $output = preg_replace('#<div id="delete-action">(.*?)</div>#', ' ', $incoming_data); [/code] Sep 29, 2016 at 11:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.