5

Since yesterday the wp_scheduled_auto_draft_delete cron job somehow deletes all page entries from our menus. All entries in the table wp_postmeta with meta_key = '_menu_item_object' and meta_value = 'page' get deleted in the process. By tracing back the DELETE query I found out that the menu entries are deleted by a function called _wp_delete_post_menu_item. I got the following stacktrace for that function:

#0  _wp_delete_post_menu_item(3244)
#1  call_user_func_array(_wp_delete_post_menu_item, Array ([0] => 3244))
called at [/srv/www/htdocs/biva/wp-includes/plugin.php:470]
#2  do_action(delete_post, 3244) called at
[/srv/www/htdocs/biva/wp-includes/post.php:2483]
#3  wp_delete_post(3244, 1) called at
[/srv/www/htdocs/biva/wp-includes/post.php:5645]
#4  wp_delete_auto_drafts()
#5  call_user_func_array(wp_delete_auto_drafts, Array ()) called at
[/srv/www/htdocs/biva/wp-includes/plugin.php:546]
#6  do_action_ref_array(wp_scheduled_auto_draft_delete, Array ()) called
at [/srv/www/htdocs/biva/wp-cron.php:100]

But I'm stuck here, I'm not a wordpress developer and I have no clue why deleting old drafts results in deleting attached menu entries although the main pages still exist.

Workaround: As a workaround we added the following to the top of wp-config, wich will disable wp-cron:

/** Disable wp-cron to prevent menu from getting deleted. Detailed Bug description:
http://wordpress.stackexchange.com/questions/145953 **/
define('DISABLE_WP_CRON', true);

If you are experiencing similar difficulties you might try locking the rows in the table wp_postmeta with meta_key = '_menu_item_object' and meta_value = 'page' and then tracing back the error message when WP trys to delete these rows, that's how we nailed down our error.

Reproduce the Error: It is definitely the stealth publish plugin that is causing our error, one can easily reproduce it, by doing the following:

  1. Install a fresh Wordpress 3.9.1.
  2. Install the stealth publish plugin http://wordpress.org/plugins/stealth-publish.
  3. Create a few test pages and add them to a new menu.
  4. Create a new page, with some dummy content, but do not save it!. Leave the page without saving.
  5. Change the system time 8 days into the future.
  6. The wp_scheduled_auto_draft_delete cron job will run because it runs daily and it hasn't run for 7 days as soon as you visit your page. It will then find your never saved dummy page delete it as it is older than 7 days and the menu will vanish.
  7. You might need to refresh the page a few times till the effect becomes visible.

I've recorded a screencast on how to reproduce the error (but I took not the time to comment it): http://www.youtube.com/watch?v=R9CTggjIfDY

10
  • This is very strange. Auto draft only exists in that brief time when you open editor to start on a new post, but hadn't saved it even once. Why would item like that have menu items associated with it? Puzzling.
    – Rarst
    Commented May 30, 2014 at 10:15
  • I guess it only occurs when there are actually some drafts older than 7 days (we have a lot of drafts). Because the bug would not occur when running wp_scheduled_auto_draft_delete twice in a short time frame. For debugging purpose I always reset the DB to the problematic state to reproduce the conditions. I believe that may also explain why others are experiencing this bug in larger time frames, assuming they have not that many drafts as we have.
    – Gellweiler
    Commented May 30, 2014 at 10:33
  • Yes, but (1) you cannot add auto-draft to menu, (2) as soon as you save it — it's no longer auto-draft. So logically these conditions cannot coincide. Question is why do they coincide in practice.
    – Rarst
    Commented May 30, 2014 at 10:35
  • If you have DB state could you please dump and add to the question post item 3244 and all menu items with meta _menu_item_object_id=3244 ?
    – Rarst
    Commented May 30, 2014 at 10:36
  • 2
    Without stealth publish everything seems to run fine. Thanks a lot for your help.
    – Gellweiler
    Commented May 30, 2014 at 11:58

1 Answer 1

5

This is what normal query run by wp_get_associated_nav_menu_items() looks like:

SELECT wp_posts.* 
FROM   wp_posts 
       INNER JOIN wp_postmeta 
               ON ( wp_posts.id = wp_postmeta.post_id ) 
WHERE  1 = 1 
       AND wp_posts.post_type = 'nav_menu_item' 
       AND (( wp_posts.post_status <> 'trash' 
              AND wp_posts.post_status <> 'auto-draft' )) 
       AND (( wp_postmeta.meta_key = '_menu_item_object_id' 
              AND Cast(wp_postmeta.meta_value AS CHAR) = '3111' )) 
GROUP  BY wp_posts.id 
ORDER  BY wp_posts.post_date DESC 

This is what yours looks like:

SELECT wp_posts.* 
FROM   wp_posts 
       INNER JOIN wp_postmeta 
               ON ( wp_posts.id = wp_postmeta.post_id ) 
       LEFT JOIN wp_postmeta AS mt1 
              ON ( wp_posts.id = mt1.post_id 
                   AND mt1.meta_key = '_stealth-publish' ) 
       INNER JOIN wp_postmeta AS mt2 
               ON ( wp_posts.id = mt2.post_id ) 
WHERE  1 = 1 
       AND wp_posts.post_type = 'nav_menu_item' 
       AND (( wp_posts.post_status <> 'trash' 
              AND wp_posts.post_status <> 'auto-draft' )) 
       AND ( ( wp_postmeta.meta_key = '_menu_item_object_id' 
               AND Cast(wp_postmeta.meta_value AS CHAR) = '3244' ) 
              OR mt1.post_id IS NULL 
              OR ( mt2.meta_key = '_stealth-publish' 
                   AND Cast(mt2.meta_value AS CHAR) != '1' ) ) 
GROUP  BY wp_posts.id 
ORDER  BY wp_posts.post_date DESC 

It would be my guess that _stealth-publish stuff has no business whatsoever interfering with querying for nav menu items.

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.