diff --git a/fieldable_panels_panes.install b/fieldable_panels_panes.install index bebedb3..ff7d18c 100644 --- a/fieldable_panels_panes.install +++ b/fieldable_panels_panes.install @@ -33,6 +33,7 @@ function fieldable_panels_panes_uninstall() { variable_del('fieldable_panels_panes_skip_default_type'); variable_del('fpp_blocks_expose'); variable_del('fpp_revision_locking'); + variable_del('fpp_change_reusability'); // Delete any variables that begin with 'fpp_expose_'. $results = db_query('SELECT name FROM {variable} WHERE name LIKE :var', array(':var' => 'fpp_expose_%'))->fetchCol(); @@ -380,7 +381,7 @@ function fieldable_panels_panes_update_7108() { // Store possible existing bundles provided by other modules. $bundles = array(); $entity_info = entity_get_info('fieldable_panels_pane'); - + // No bundles defined. This could happen if the module was updated and cache // cleared before update was run as entity info's cache will no longer // contain the old default. @@ -392,7 +393,7 @@ function fieldable_panels_panes_update_7108() { ), ); } - + foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) { $bundles[] = $bundle_info['label']; @@ -428,3 +429,87 @@ function fieldable_panels_panes_update_7109() { function fieldable_panels_panes_update_7110() { variable_set('menu_rebuild_needed', TRUE); } + +/** + * Existing sites will disable locking. + */ +function fieldable_panels_panes_update_7111() { + variable_set('fpp_revision_locking', 'legacy'); +} + +/** + * Update all Panelizer displays to point non-reusable FPPs to the vid instead + * of the fpid. + */ +function fieldable_panels_panes_update_7112(&$sandbox) { + if (!module_exists('panelizer')) { + return t('Panelizer is not installed, so nothing to do.'); + } + + if (variable_get('fpp_revision_locking', 'lock') != 'lock') { + return t('Pane locking is not enabled, so nothing to do.'); + } + + // Update all Panelizer displays. + if (!isset($sandbox['progress'])) { + $sandbox['progress'] = 0; + $sandbox['limit'] = 1; + } + + // Get a list of all FPIDs for Panelizer displays. + $results = db_query("SELECT DISTINCT fpp.fpid as fpid, fpp.vid as vid + FROM {fieldable_panels_panes} fpp + INNER JOIN {panels_pane} pp + ON fpp.fpid = SUBSTRING_INDEX(pp.subtype, ':', -1) + INNER JOIN {panelizer_entity} pe + ON pe.did = pp.did + WHERE (pp.subtype LIKE 'fpid:%' OR pp.subtype LIKE 'current:%') + AND fpp.reusable != 1 + ORDER BY fpp.fpid"); + + // If there are no records, there's nothing to do. + if ($results->rowCount() == 0) { + return t('No records need fixing.'); + } + + // Total records that must be processed. + $sandbox['max'] = $results->rowCount(); + + // Loop through the FPPs. + foreach ($results as $record) { + $fstr = 'fpid:' . $record->fpid; + $vstr = 'vid:' . $record->vid; + // Check to see if there is a matching panel pane. + $sql = db_query('SELECT pid FROM {panels_pane} WHERE subtype = :var', array(':var' => $fstr))->fetchCol(); + + if (!empty($sql)) { + // If there is a matching panel pane, update the fpids to vids. + $query = db_update('panels_pane') + ->fields(array('subtype' => $vstr)) + ->condition('subtype', $fstr) + ->execute(); + } + // Increment $sandbox + $sandbox['progress']++; + } + + $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']); + + return t('Fixed @count record(s) (out of @total) that were using the same display.', array('@count' => $sandbox['progress'], '@total' => $sandbox['max'])); +} + +/** + * Update all Panel Nodes displays to point non-reusable FPPs to the vid instead + * of the fpid. + */ +function fieldable_panels_panes_update_7113() { + if (!module_exists('panels_node')) { + return t('Panel Nodes is not installed, so nothing to do.'); + } + + if (variable_get('fpp_revision_locking', 'lock') != 'lock') { + return t('Pane locking is not enabled, so nothing to do.'); + } + + // @todo Update all Panel Nodes displays. +} diff --git a/fieldable_panels_panes.module b/fieldable_panels_panes.module index 5f381d7..aebeb89 100644 --- a/fieldable_panels_panes.module +++ b/fieldable_panels_panes.module @@ -1291,29 +1291,10 @@ function fieldable_panels_panes_entity_edit_form($form, &$form_state) { ), ), '#weight' => 10, + // It's dangerous to change an FPP's reusability after it is created. + '#access' => empty($entity->fpid) || variable_get('fpp_change_reusability', FALSE), ); - $form['revision'] = array( - '#type' => 'fieldset', - '#title' => t('Revision'), - '#collapsible' => TRUE, - '#collapsed' => empty($entity->revision), - '#group' => 'additional_settings', - '#attributes' => array( - 'class' => array('fieldable-pane-pane-form-revision-information'), - ), - '#attached' => array( - 'js' => array( - 'vertical-tabs' => drupal_get_path('module', 'fieldable_panels_panes') . '/fieldable_panels_panes.vertical-tabs.js', - ), - ), - '#weight' => 30, - ); - - if (empty($entity->fpid)) { - $form['revision']['#access'] = FALSE; - } - $form['reusable']['reusable'] = array( '#type' => 'checkbox', '#title' => t('Make this entity reusable'), @@ -1356,21 +1337,50 @@ function fieldable_panels_panes_entity_edit_form($form, &$form_state) { ), ); + $form['revision'] = array( + '#type' => 'fieldset', + '#title' => t('Revision'), + '#collapsible' => TRUE, + '#collapsed' => empty($entity->revision), + '#group' => 'additional_settings', + '#attributes' => array( + 'class' => array('fieldable-pane-pane-form-revision-information'), + ), + '#attached' => array( + 'js' => array( + 'vertical-tabs' => drupal_get_path('module', 'fieldable_panels_panes') . '/fieldable_panels_panes.vertical-tabs.js', + ), + ), + '#weight' => 30, + '#access' => empty($entity->fpid), + ); + $form['revision']['revision'] = array( '#type' => 'checkbox', '#title' => t('Create new revision'), '#default_value' => 1, ); - if (!user_access('administer fieldable panels panes') || $entity->vid != $entity->current_vid) { + // Force a new revision to be created if the user does not have 'admin FPP' + // access, or the 'lock' mode was enabled and this is not a reusable FPP. + if (!user_access('administer fieldable panels panes') + || $entity->vid != $entity->current_vid + || (!empty($entity->fpid) && empty($entity->reusable) + && variable_get('fpp_revision_locking', 'lock') == 'lock')) { $form['revision']['revision']['#disabled'] = TRUE; $form['revision']['revision']['#value'] = TRUE; + + // Inform the user that the pane will be locked. + if (!empty($entity->fpid) && empty($entity->reusable) + && variable_get('fpp_revision_locking', 'lock') == 'lock') { + $form['revision']['revision']['#description'] = t('A new revision will be created because this pane is non-reusable and the locking mode has been enabled.'); + } } $form['revision']['log'] = array( '#type' => 'textarea', '#title' => t('Log message'), - '#description' => t('Provide an explanation of the changes you are making. This will help other authors understand your motivations.'), + '#description' => t('Provide an explanation of the changes being made.'), '#default_value' => '', '#states' => array( 'visible' => array( @@ -1553,18 +1563,13 @@ function fieldable_panels_panes_file_download_access($field, $entity_type, $enti * @return bool */ function fieldable_panels_panes_revision_is_lockable($entity) { - $lock = variable_get('fpp_revision_locking', 'legacy'); + $lock = variable_get('fpp_revision_locking', 'lock'); // Only non-reusable FPPs will be lockable. if ($lock == 'lock') { $revision_context_aware = empty($entity->reusable); } - // Lock all revisions, even reusable FPPs. - elseif ($lock == 'lock_all') { - $revision_context_aware = TRUE; - } - // Legacy mode, no revisions handling. else { $revision_context_aware = FALSE; diff --git a/includes/PanelsPaneController.class.php b/includes/PanelsPaneController.class.php index b62a934..6c7f1ea 100644 --- a/includes/PanelsPaneController.class.php +++ b/includes/PanelsPaneController.class.php @@ -239,7 +239,10 @@ public function view($entity, $view_mode = 'full', $langcode = NULL) { // behavior (for example, to restrict contextual links to certain view // modes) by implementing hook_fieldable_panels_pane_view_alter(). if (!empty($entity->fpid) && !($view_mode == 'full' && fieldable_panels_pane_is_page($entity))) { - $build['#contextual_links']['fieldable_panels_panes'] = array('admin/structure/fieldable-panels-panes/view', array($entity->fpid)); + // Allow the contextual links to be controlled from the settings page. + if (!variable_get('fpp_hide_contextual_links', FALSE)) { + $build['#contextual_links']['fieldable_panels_panes'] = array('admin/structure/fieldable-panels-panes/view', array($entity->fpid)); + } } // Allow modules to modify the structured pane. diff --git a/includes/admin.inc b/includes/admin.inc index c93e504..778ca17 100644 --- a/includes/admin.inc +++ b/includes/admin.inc @@ -13,14 +13,28 @@ function fieldable_panels_panes_settings() { $form['fpp_revision_locking'] = array( '#type' => 'radios', - '#title' => t('Should FPP ctools content reference FPP entities by entity ID or revision ID?'), - '#description' => t('For example, using a panelized entity, you can revert the entity to previous revision and FPPs will also revert if they are referenced by revision ID.'), + '#title' => t('Should FPP CTools content panes reference FPP entities by entity ID or revision ID?'), + '#description' => t('For example, a panelized entity can revert the entity to previous revision and FPPs will also revert if they are referenced by revision ID. This also allows for editorial workflows using e.g. the Workbench Moderation or Revisioning modules.'), '#options' => array( - 'legacy' => t('Legacy: use entity ID for all FPPs.'), - 'lock' => t('Recommended: Use revision ID for non-reusable FPPs only.'), - 'lock_all' => t('Use revision ID for all FPPs.'), + 'legacy' => t('Legacy: Use entity ID for all FPPs.'), + 'lock' => t('Recommended: Use revision ID for non-reusable FPPs only; will also force each FPP update to create a new revision.'), ), - '#default_value' => variable_get('fpp_revision_locking', 'legacy'), + '#default_value' => variable_get('fpp_revision_locking', 'lock'), + ); + + $form['fpp_change_reusability'] = array( + '#type' => 'checkbox', + '#title' => t('Allow the "reusable" option to be changed after initial creation?'), + '#description' => t('It is recommended to not enable this option, it can lead to potential problems when using the "recommended" locking scheme is enabled above.'), + '#default_value' => variable_get('fpp_change_reusability', FALSE), + ); + + $form['fpp_hide_contextual_links'] = array( + '#type' => 'checkbox', + '#title' => t('Hide the FPP contextual menus?'), + '#description' => t('Being able to edit FPPs directly can cause problems with the editorial workflows when using e.g. Panelizer.'), + '#default_value' => variable_get('fpp_hide_contextual_links', FALSE), + '#disabled' => !module_exists('contextual'), ); $form['fpp_blocks_expose'] = array( diff --git a/plugins/content_types/fieldable_panels_pane.inc b/plugins/content_types/fieldable_panels_pane.inc index 0a12b36..5bf2191 100644 --- a/plugins/content_types/fieldable_panels_pane.inc +++ b/plugins/content_types/fieldable_panels_pane.inc @@ -147,6 +147,39 @@ function fieldable_panels_panes_fieldable_panels_pane_content_type_render($subty } } + // Add an indicator on the workflow statuses. + $reusable = !empty($entity->reusable); + $args = array( + '@reusable' => $reusable ? t('Reusable.') : t('Not reusable.'), + ); + $block->content['#suffix'] = t("
\nPane is: @reusable
\n", $args); + + // Node revisions open up the possibility of revisioning. The path will be + // either node/[nid]/panelizer/[viewmode]/content or + // node/[nid]/revisions/[vid]/panelizer/[viewmode]/content + // or panels/ajax/editor/add-pane/panelizer:node:. + // @todo There should be way of identifying the path via APIs instead of + // hardcoding it like this. + if ((arg(0) == 'node' && (arg(2) == 'panelizer' || (arg(2) == 'revisions' && arg(4) == 'panelizer'))) + || (arg(0) == 'panels' && arg(1) == 'ajax' && arg(2) == 'editor' && arg(3) == 'add-pane' && strpos(arg(4), ':node:'))) { + $locking = variable_get('fpp_revision_locking', 'lock'); + if ($locking == 'lock' && !$reusable) { + $args['@locking'] = t('If a new revision is saved for this node and a new FPP revision is created, the changes in this FPP will be saved to the new node revision.'); + } + elseif (!empty($reusable)) { + $args['@locking'] = t('Will take effect immediately and affect every page the pane is on.'); + } + else { + $args['@locking'] = t('Will take effect immediately.'); + } + $block->content['#suffix'] .= t("Changes: @locking\n", $args); + } + // Add a warning about editing reusable panes. + elseif (!empty($reusable)) { + $args['@locking'] = t('Will take effect immediately and affect every page the pane is on.'); + $block->content['#suffix'] .= t("Changes: @locking\n", $args); + } + return $block; } } @@ -164,6 +197,14 @@ function fieldable_panels_panes_fieldable_panels_pane_content_type_admin_title($ $output = t('Deleted/removed entity pane'); } + // Indicate whether the FPP is reusable. + if (!empty($entity->reusable)) { + $output .= ' (' . t('reusable') . ')'; + } + else { + $output .= ' (' . t('not reusable') . ')'; + } + return $output; }