diff --git a/amp.info b/amp.info index 0a4bba2..522f740 100644 --- a/amp.info +++ b/amp.info @@ -6,3 +6,4 @@ php = 5.5 dependencies[] = token dependencies[] = ctools files[] = tests/amp.test +files[] = tests/amp_node.test diff --git a/amp.install b/amp.install index fcb6a71..04ae6cd 100644 --- a/amp.install +++ b/amp.install @@ -50,6 +50,51 @@ function amp_requirements($phase) { } /** + * Implements hook_install. + * + * Add new table for unpublished AMP nodes. + */ +function amp_schema() { + $schema['amp_node'] = array( + 'description' => 'Stores preferences for amp nodes.', + 'primary key' => array('aid'), + 'fields' => array( + 'aid' => array( + 'description' => 'The {amp}.id of the amp node.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'status' => array( + 'description' => 'Boolean indicating whether the node is AMP enabled by default.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 1, + 'size' => 'tiny', + ), + ), + 'indexes' => array( + 'aid' => array('aid'), + 'status' => array('status'), + ), + ); + + return $schema; +} + +/** + * Add new table to track unpublished AMP nodes. + */ +function amp_update_7001() { + if (!db_table_exists('amp_node')) { + drupal_install_schema('amp'); + } + +} + +/** * Implements hook_uninstall(). */ function amp_uninstall() { diff --git a/amp.module b/amp.module index 717ef33..cd574db 100644 --- a/amp.module +++ b/amp.module @@ -6,6 +6,7 @@ */ require_once dirname(__FILE__).'/amp.admin.inc'; +require_once dirname(__FILE__) . '/includes/amp.db.inc'; use Lullabot\AMP\AMP; use Lullabot\AMP\Validate\Scope; @@ -341,14 +342,17 @@ function amp_is_amp_request() { // it is a node type which has the AMP view mode enabled. $node = menu_get_object(); if ($node && in_array($node->type, amp_get_enabled_types())) { - // Do an additional check to ensure the current path is actually the - // node's public URI. Without this check, this function would return - // TRUE on the node's edit form. - $uri = entity_uri('node', $node); - if ($uri['path'] == current_path()) { - // Only if all of the above conditions are true is this a valid AMP - // request. - $result = TRUE; + // Node level check. + if (amp_node_is_enabled($node->nid)) { + // Do an additional check to ensure the current path is actually the + // node's public URI. Without this check, this function would return + // TRUE on the node's edit form. + $uri = entity_uri('node', $node); + if ($uri['path'] == current_path()) { + // Only if all of the above conditions are true is this a valid AMP + // request. + $result = TRUE; + } } } } @@ -388,7 +392,7 @@ function amp_form_node_form_alter(&$form, &$form_state, $form_id) { $form['actions']['save_view_amp'] = array( '#type' => 'submit', '#value' => t('Save and view AMP page'), - '#submit' => array('node_form_submit', 'amp_node_form_submit'), + '#submit' => array('node_form_submit', 'amp_node_enabled_form_submit', 'amp_node_form_submit'), '#weight' => 12, '#access' => TRUE, ); @@ -396,10 +400,42 @@ function amp_form_node_form_alter(&$form, &$form_state, $form_id) { $form['actions']['save_view_amp_warnfix'] = array( '#type' => 'submit', '#value' => t('Save and view AMP page and see any AMP formatter warnings'), - '#submit' => array('node_form_submit', 'amp_node_form_submit_warnfix'), + '#submit' => array('node_form_submit', 'amp_node_enabled_form_submit', 'amp_node_form_submit_warnfix'), '#weight' => 13, '#access' => TRUE, ); + + // Option to disable AMP. + // When adding new nodes, AMP will be turned on by default. + $amp_enabled = 1; + // If we are editing an existing node, get the value from database. + if (isset($form_state['node']->nid) && !amp_db_is_node_enabled($form_state['node']->nid)) { + $amp_enabled = 0; + } + $form['options']['amp_enabled'] = array( + '#title' => t('Published (AMP)'), + '#type' => 'checkbox', + '#default_value' => $amp_enabled, + ); + + // Form callback for node enabled. + $form['actions']['submit']['#submit'][] = 'amp_node_enabled_form_submit'; + } +} + +/** + * Form callback to save the enabled status. + */ +function amp_node_enabled_form_submit(&$form, $form_state) { + if (isset($form_state['node']->nid)) { + $node_id = $form_state['node']->nid; + if ($form_state['values']['amp_enabled'] == 1) { + amp_db_enable_amp($node_id); + } + else { + amp_db_disable_amp($node_id); + } + amp_clear_cache($node_id); } } @@ -645,8 +681,14 @@ function amp_page_alter(array &$page) { * Implements hook_node_view(). */ function amp_node_view($node, $view_mode, $langcode) { + if ($node = menu_get_object()) { + if (!in_array($node->type, amp_get_enabled_types()) || !amp_node_is_enabled($node->nid)) { + return; + } + } + // Show amphtml links on AMP-enabled nodes so search engines can find AMP. - if ($view_mode == 'full' && node_is_page($node) && in_array($node->type, amp_get_enabled_types())) { + if ($view_mode == 'full' && node_is_page($node)) { $uri = entity_uri('node', $node); $uri['options']['query']['amp'] = NULL; $uri['options']['absolute'] = TRUE; @@ -1450,6 +1492,54 @@ function amp_page_delivery_callback_alter(&$deliver_callback) { } /** + * Implements hook_node_delete(). + */ +function amp_node_delete($node) { + if (in_array($node->type, amp_get_enabled_types())) { + // We don't need the amp table for this node if it gets removed. + amp_db_remove($node->nid); + amp_clear_cache($node->nid); + } +} + +/** + * Clear cache with id $id + * + * @param $id + * ID of the cache to clear. + */ +function amp_clear_cache($id) { + // Clear bins as we have fresh data. + cache_clear_all('amp:node_enabled:' . $id, 'cache'); +} + +/** + * Get if the node is enabled. + * + * @param $node_id + * Node id to check. + * + * @return bool + * TRUE if enabled, FALSE otherwise. + */ +function amp_node_is_enabled($node_id, $cache_override = FALSE) { + // Setup a cache ID + $cid = 'amp:node_enabled:' . $node_id; + + // If a cached entry exists, return it + if (($cache = cache_get($cid, 'cache')) && $cache_override != TRUE) { + $is_enabled = $cache->data; + } + else { + $is_enabled = amp_db_is_node_enabled($node_id); + // Cache the result. + cache_set($cid, $is_enabled, 'cache'); + } + + return $is_enabled; +} + +/** * Implements hook_html_head_alter(). */ function amp_html_head_alter(&$head_elements) { diff --git a/includes/amp.db.inc b/includes/amp.db.inc new file mode 100644 index 0000000..2adcbce --- /dev/null +++ b/includes/amp.db.inc @@ -0,0 +1,80 @@ +fields('n', array('status')) + ->condition('aid', $node_id, '=') + ->execute() + ->fetchAll(); + + // If we don't have an entry as disabled (!empty()), AMP is enabled by default + if (isset($result[0]->status) && $result[0]->status == AMP_DISABLED) { + $is_enabled = FALSE; + } + + return $is_enabled; +} + +/** + * Set a node as AMP disabled. + * + * @param $node_id + * Node ID of the node to set as disabled. + * + * @throws \Exception + */ +function amp_db_disable_amp($node_id) { + db_merge('amp_node') + ->key(array('aid' => $node_id)) + ->fields(array('status' => AMP_DISABLED)) + ->execute(); +} + +/** + * Set a node as AMP enabled. + * + * @param $node_id + * Node ID of the node to set as enabled. + * + * @throws \Exception + */ +function amp_db_enable_amp($node_id) { + // Enable removes the flag from the db. + amp_db_remove($node_id); +} + +/** + * Remove a given node from AMP. + * + * @param $node_id + * Node ID to remove. + * + * @throws \Exception + */ +function amp_db_remove($node_id) { + // Deleting it from the table will set it up as enabled by default and will + // keep the table as small as possible. + db_delete('amp_node') + ->condition('aid', $node_id) + ->execute(); +} diff --git a/modules/amp_dfp/amp_dfp.module b/modules/amp_dfp/amp_dfp.module index 771198f..f80ad90 100644 --- a/modules/amp_dfp/amp_dfp.module +++ b/modules/amp_dfp/amp_dfp.module @@ -36,6 +36,9 @@ function amp_dfp_theme($existing, $type, $theme, $path) { * Implements hook_preprocess_amp_dfp_tag(). */ function amp_dfp_preprocess_amp_dfp_tag(&$variables) { + if (!amp_is_amp_request()) { + return; + } $variables['layout'] = $variables['tag']->settings['amp_layout']; $size = _amp_dfp_get_amp_size($variables['tag']); if (empty($size)) { diff --git a/tests/amp_node.test b/tests/amp_node.test new file mode 100644 index 0000000..effdaea --- /dev/null +++ b/tests/amp_node.test @@ -0,0 +1,79 @@ + 'AMP node switch', + 'description' => 'Tests AMP switch on node level.', + 'group' => 'AMP', + ); + } + + protected function setUp() { + // Enable AMP module. + parent::setUp('field_ui', 'amp_test'); + + // Create Admin user. + $this->admin_user = $this->drupalCreateUser(array( + 'administer content types', + 'administer nodes', + 'edit any article content', + 'administer fields', + ) + ); + $this->drupalLogin($this->admin_user); + } + + /** + * Test the AMP view mode. + */ + public function testAmpNodeSwitch() { + // Login as an admin user. + $this->drupalLogin($this->admin_user); + + // Create a node to test AMP metadata. + $node = $this->drupalCreateNode(array('type' => 'article')); + + // Enable AMP display on article content. + $this->drupalGet("admin/structure/types/manage/article/display"); + $this->assertResponse(200); + $edit = ["view_modes_custom[amp]" => '1']; + $this->drupalPost(NULL, $edit, t('Save')); + + // Amp version of node should be enabled by default. + $this->drupalGet('node/' . $node->nid); + $this->assertResponse(200); + // Check amphtml link. + $pattern = '||'; + $this->assertPattern($pattern, 'Check that link rel="amphtml" is present on the page.'); + // Visit amp page. + $this->drupalGet('node/' . $node->nid, array('query' => array('amp' => TRUE))); + $this->assertResponse(200); + $this->assertText($node->body[LANGUAGE_NONE][0]['value']); + // Check canonical link. + $pattern = '||'; + $this->assertPattern($pattern, 'Check that link rel="canonical" is present on the page.'); + + // Edit the node and turn off AMP. + $this->drupalGet('node/' . $node->nid . '/edit'); + $this->assertResponse(200); + $edit = [ + 'amp_enabled' => FALSE, + ]; + $this->drupalPost(NULL, $edit, t('Save')); + + // View node. + $this->drupalGet('node/' . $node->nid); + $this->assertResponse(200); + // Check that amphtml link is not present. + $pattern = '||'; + $this->assertNoPattern($pattern, 'Check that link rel="amphtml" is present on the page.'); + } +}