6

I'm working on a plugin that interacts with Gravity Forms, and under certain conditions I want to prevent a form from being deleted. Here's the method in Gravity Forms that handles deleting a form:

public static function delete_form($form_id){
    global $wpdb;

    if(!GFCommon::current_user_can_any("gravityforms_delete_forms"))
        die(__("You don't have adequate permission to delete forms.", "gravityforms"));

    do_action("gform_before_delete_form", $form_id);

    $form_meta_table = self::get_meta_table_name();
    $form_table = self::get_form_table_name();

    //Deleting form Entries
    self::delete_leads_by_form($form_id);

    //Delete form meta
    $sql = $wpdb->prepare("DELETE FROM $form_meta_table WHERE form_id=%d", $form_id);
    $wpdb->query($sql);

    //Deleting form Views
    self::delete_views($form_id);

    //Delete form
    $sql = $wpdb->prepare("DELETE FROM $form_table WHERE id=%d", $form_id);
    $wpdb->query($sql);

    do_action("gform_after_delete_form", $form_id);
}

Is it possible to hook into gform_before_delete_form and then do something to make delete_form() return at that point without continuing? e.g.,

public function preventGravityFormDeletion()
{
    if( $someCondition )
    {
        // do something that forces delete_form() to stop
    }
}
add_action( 'gform_before_delete_form', array( $this, 'preventGravityFormDeletion' ) );

I know that I could call wp_die() and just stop everything, but that's not very elegant. Is there a better way? It doesn't seem possible because of scope limitations, but I wanted to check in case there's some WP/PHP magic that I'm not aware of.

2
  • Would this question be better-asked at the Gravity Forms support forum? Or is the GF part just to give context to the question regarding removing/preventing actions from firing? Feb 10, 2012 at 14:42
  • Yeah, it was just to give a concrete example, but I think the question could apply to lots of other situations as well.
    – Ian Dunn
    Feb 10, 2012 at 15:20

3 Answers 3

4

Short answer: no.

Long answer: also no. Actions don't work that way.

Edit:

To elaborate and make your question totally generic:

function foo() {
  bar();
  return 1;
}

function bar() {
  // stuff
}

There is nothing you can put in stuff that will prevent a call to foo() from returning 1, other than halting script execution entirely with die or exit.

Note: Throwing exceptions won't help either, because this has the same effect as halting script execution unless some previous caller catches the exeception.

Now, if this function is in a class somewhere, then you can define a subclass of it and replace this function with one of your own, then potentially use that, thus modifying the way this function works. That's about the best you can do, since PHP doesn't have any sort of aspect-oriented-programming mechanisms in it that would allow you to change function behavior at runtime.

6
  • I realize that it's probably not possible, but I already stated that up front in the question, so your answer doesn't really add anything new to the topic. At the very least, you should explain WHY the answer is no, instead of just saying, "it doesn't work that way." What I was really looking for was some kind of obscure or creative, non-obvious solution, and your answer doesn't give me any confidence that you even considered anything like that before firing off a quick reply.
    – Ian Dunn
    Feb 10, 2012 at 15:27
  • 2
    Okay. You can't make it return from a do_action because it's not calling it with return do_action and also because actions don't return values to check for. There's no obscure or non-obvious solution, because code doesn't work that way. The most you can make the thing do is exit early with die() or exit(), which you already recognized in your question and so I didn't feel the need to elaborate on. Basically, you want to know how a called function can make the function its called from behave in a way other than it's written. Answer: You can't do that, because PHP has no way to do that.
    – Otto
    Feb 11, 2012 at 7:17
  • @IanDunn There's no reason to berate others trying to help. :) :) Feb 11, 2012 at 8:59
  • Brian, I just re-read my comment and I really don't think the tone qualifies as "berating," but I'll admit I was definitely frustrated when I wrote it, so I apologize if it came across as harsh. I thought Otto's original answer was dismissive and a little condescending, in addition to not actually offering any kind of solution, and that was frustrating. Any first-year CS major could tell me the obvious answer; I was looking for a more thoughtful and creative answer, but I should have communicated that better in the question.
    – Ian Dunn
    Feb 11, 2012 at 17:02
  • Otto, thanks for the revised answer. Overriding the method is a good thought, but I don't think it would work because the parent method would still be called instead of the child. Some other thoughts I've had include modifying the view files to remove the delete links, and asking the GF devs to add a filter that could trigger an early return, but neither of those are very promising. I still think that claiming it absolutely can't be done is short-sighted, though. It's entirely possible that there are hacks, workarounds, or different approaches we just haven't thought of yet.
    – Ian Dunn
    Feb 11, 2012 at 17:23
7

A creative solution would be to modify the actual form_id in the database during gform_before_delete_form so none of the proceeding actions will modify the form.

Then you can hook into gform_after_delete_form and modify the form_id back.

gform_before_delete_form

form_id = form_id + 1000000

gform_after_delete_form

form_id = form_id - 1000000 

(assuming you have less than a million forms!)

rough code:

public function preventGravityFormDeletion()
{
if( $someCondition )
    {
    global $wpdb;
    $temp_form_id = 1000000+$form_id;
    $sql = $wpdb->prepare("UPDATE $form_meta_table SET form_id = $temp_form_id WHERE form_id=$form_id");
    $wpdb->query($sql);
    $sql = $wpdb->prepare("UPDATE $form_table SET id = $temp_form_id WHERE id=$form_id");
    $wpdb->query($sql);
    }
}
add_action( 'gform_before_delete_form', array( $this, 'preventGravityFormDeletion' ) );
2
  • 1
    That's a very smart solution and IMHO it should be the accepted answer :) (well, I have to take into account the fact that you wrote it a year after Otto's answer and I'm writing this comment two years later :) ). Feb 13, 2015 at 13:13
  • Unfortunately this no longer works. But... gforms provides a new working method. See my answer. Feb 3, 2021 at 21:09
1

For those looking, Gravity Forms now provides this solution:

add_filter( 'gform_form_trash_link', 'prevent_form_deletion', 10, 2 );

function prevent_form_deletion( $trash_link, $form_id ){ if ( $form_id == 75 ) { $trash_link = '<a class="submitdelete" onclick="alert(\'This form cannot be deleted.\');" onkeypress="alert(\'This form cannot be deleted.\')">Remove this Form</a>'; } return $trash_link; }

https://docs.gravityforms.com/gform_form_trash_link/

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.