diff --git a/amp.install b/amp.install index 2a0acda..bae876c 100644 --- a/amp.install +++ b/amp.install @@ -48,3 +48,48 @@ function amp_requirements($phase) { } return $requirements; } + +/** + * 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'); + } + +} diff --git a/amp.module b/amp.module index 3792dba..bfdd086 100644 --- a/amp.module +++ b/amp.module @@ -361,9 +361,15 @@ function amp_is_amp_request() { * Implements hook_custom_theme(). */ function amp_custom_theme() { - if (amp_is_amp_request()) { - return variable_get('amp_theme', 'ampsubtheme_example'); - } + $node = menu_get_object(); + + if (amp_is_amp_request()) { + // Performance note: Just load this file when we know is an AMP request. + module_load_include('inc', 'amp', 'inc/amp.db'); + if (amp_node_is_enabled($node->nid)) { + return variable_get('amp_theme', 'ampsubtheme_example'); + } + } } /** @@ -373,7 +379,12 @@ function amp_custom_theme() { */ function amp_entity_view_mode_alter(&$view_mode, $context) { if ($view_mode === 'full' && amp_is_amp_request()) { - $view_mode = 'amp'; + // Performance note: Just load this file when we know is an AMP request. + module_load_include('inc', 'amp', 'inc/amp.db'); + $node = menu_get_object(); + if (amp_node_is_enabled($node->nid)) { + $view_mode = 'amp'; + } } } @@ -400,6 +411,38 @@ function amp_form_node_form_alter(&$form, &$form_state, $form_id) { '#weight' => 13, '#access' => TRUE, ); + + module_load_include('inc', 'amp', 'inc/amp.db'); + // Disable amp checkbox. + $form['options']['amp_enabled'] = array( + '#title' => t('Published (AMP)'), + '#type' => 'checkbox', + // if AMP_disabled == TRUE, means AMP is enabled, or AMP_enabled == FALSE; + '#default_value' => amp_node_is_enabled($form_state['node']->nid), + ); + + $form['actions']['submit']['#submit'][] = 'amp_form_submit'; + } +} + +/** + * Implements amp_form_submit. + */ +function amp_form_submit($form, &$form_state) { + module_load_include('inc', 'amp', 'inc/amp.db'); + if ($form_state['values']['amp_enabled'] == 0) { + amp_db_disable_amp($form_state['nid']); + amp_clear_cache($form_state['nid']); + } + elseif ($form_state['values']['amp_enabled'] == 1 && !amp_node_is_enabled($form_state['nid'])) { + // If the form says enable, and it was disabled, enable it back. + try { + amp_db_enable_amp($form_state['nid']); + amp_clear_cache($form_state['nid']); + } + catch (Exception $ex) { + watchdog('amp', "DB Exception: We couldn't disable the AMP version of the node"); + } } } @@ -647,10 +690,13 @@ function amp_page_alter(array &$page) { function amp_node_view($node, $view_mode, $langcode) { // 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())) { - $uri = entity_uri('node', $node); - $uri['options']['query']['amp'] = NULL; - $uri['options']['absolute'] = TRUE; - drupal_add_html_head_link(array('rel' => 'amphtml', 'href' => url($uri['path'], $uri['options'])), TRUE); + module_load_include('inc', 'amp', 'inc/amp.db'); + if (amp_node_is_enabled($build['#node']->nid)) { + $uri = entity_uri('node', $node); + $uri['options']['query']['amp'] = NULL; + $uri['options']['absolute'] = TRUE; + drupal_add_html_head_link(array('rel' => 'amphtml', 'href' => url($uri['path'], $uri['options'])), TRUE); + } } // Add AMP metadata. @@ -1444,11 +1490,65 @@ function amp_deliver_html_page($page_callback_result) { */ function amp_page_delivery_callback_alter(&$deliver_callback) { if (amp_is_amp_request()) { - $deliver_callback = 'amp_deliver_html_page'; + $node = menu_get_object(); + module_load_include('inc', 'amp', 'inc/amp.db'); + if (amp_node_is_enabled($node->nid)) { + $deliver_callback = 'amp_deliver_html_page'; + } + } +} + +/** + * 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. + module_load_include('inc', 'amp', 'inc/amp.db'); + amp_db_remove($node->nid); + amp_clear_cache($node->id); } } /** + * 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_amp'); +} + +/** + * Get if the node is enabled. + * + * @param $nodeid + * Node id to check. + * + * @return bool + * TRUE if enabled, FALSE otherwise. + */ +function amp_node_is_enabled($nodeid, $cache_override = FALSE) { + // Setup a cache ID + $cid = 'amp:node_enabled:' . $nodeid; + + // If a cached entry exists, return it + if ($cached = cache_get($cid) && $cache_override != TRUE) { + $is_enabled = $cached->data; + } + else { + $is_enabled = amp_db_is_node_enabled($nodeid); + + // Cache the result. + cache_set($cid, $is_enabled, 'cache_amp'); + } + + return $is_enabled; +} + +/** * Implements hook_html_head_alter(). */ function amp_html_head_alter(&$head_elements) { diff --git a/inc/amp.db.inc b/inc/amp.db.inc new file mode 100644 index 0000000..528a2dc --- /dev/null +++ b/inc/amp.db.inc @@ -0,0 +1,80 @@ +fields('n', array('status')) + ->condition('aid', $nodeid, '=') + ->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 == 0) { + $is_enabled = FALSE; + } + + return $is_enabled; +} + +/** + * Set a node as AMP disabled. + * + * @param $nodeid + * Node ID of the node to set as disabled. + * + * @throws \Exception + */ +function amp_db_disable_amp($nodeid) { + db_merge('amp_node') + ->key(array('aid' => $nodeid)) + ->fields(array('status' => AMP_DISABLED)) + ->execute(); +} + +/** + * Set a node as AMP enabled. + * + * @param $nodeid + * Node ID of the node to set as enabled. + * + * @throws \Exception + */ +function amp_db_enable_amp($nodeid) { + // Enable removes the flag from the db. + amp_db_remove($nodeid); +} + +/** + * Remove a given node from AMP. + * + * @param $nodeid + * Node ID to remove. + * + * @throws \Exception + */ +function amp_db_remove($nodeid) { + // 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', $nodeid) + ->execute(); +} diff --git a/modules/amp_dfp/amp_dfp.module b/modules/amp_dfp/amp_dfp.module index 9e24fcc..beb4bb2 100644 --- a/modules/amp_dfp/amp_dfp.module +++ b/modules/amp_dfp/amp_dfp.module @@ -36,41 +36,48 @@ function amp_dfp_theme($existing, $type, $theme, $path) { * Implements hook_preprocess_amp_dfp_tag(). */ function amp_dfp_preprocess_amp_dfp_tag(&$variables) { - $size = _amp_dfp_get_amp_size($variables['tag']); - if (empty($size)) { - // Provide a default if there is a problem, so validation does not break. - $variables['width'] = $variables['height'] = 1; - } else { - $variables['width'] = $size['width']; - $variables['height'] = $size['height']; - } - - $tag = _dfp_prepare_adunit($variables['tag']); - $tag->adunit = _dfp_clean_adunit(token_replace('[dfp_tag:network_id]/' . $tag->adunit, _dfp_prepare_tokens($tag), array('sanitize' => TRUE, 'clear' => TRUE))); - - // We add global targeting to each dfp tag to simplify implementation. - $global_targeting = variable_get('dfp_targeting', array()); - drupal_alter('dfp_global_targeting', $global_targeting); - $tag->global_targeting = $global_targeting; - - $variables['slot'] = $tag->adunit; - - // Prepare targeting arrays for JSON formatting - $targeting = array(); - foreach ($tag->targeting as $target) { - $targeting[$target['target']] = token_replace($target['value'], _dfp_prepare_tokens($tag), array('sanitize' => TRUE, 'clear' => TRUE)); - } - - $global_targeting = array(); - foreach ($tag->global_targeting as $target) { - $global_targeting[$target['target']] = token_replace($target['value'], _dfp_prepare_tokens($tag), array('sanitize' => TRUE, 'clear' => TRUE)); + if (amp_is_amp_request()) { + // Performance note: Just load this file when we know is an AMP request. + module_load_include('inc', 'amp', 'inc/amp.db'); + $node = menu_get_object(); + if (amp_node_is_enabled($node->nid)) { + $size = _amp_dfp_get_amp_size($variables['tag']); + if (empty($size)) { + // Provide a default if there is a problem, so validation does not break. + $variables['width'] = $variables['height'] = 1; + } else { + $variables['width'] = $size['width']; + $variables['height'] = $size['height']; + } + + $tag = _dfp_prepare_adunit($variables['tag']); + $tag->adunit = _dfp_clean_adunit(token_replace('[dfp_tag:network_id]/' . $tag->adunit, _dfp_prepare_tokens($tag), array('sanitize' => TRUE, 'clear' => TRUE))); + + // We add global targeting to each dfp tag to simplify implementation. + $global_targeting = variable_get('dfp_targeting', array()); + drupal_alter('dfp_global_targeting', $global_targeting); + $tag->global_targeting = $global_targeting; + + $variables['slot'] = $tag->adunit; + + // Prepare targeting arrays for JSON formatting + $targeting = array(); + foreach ($tag->targeting as $target) { + $targeting[$target['target']] = token_replace($target['value'], _dfp_prepare_tokens($tag), array('sanitize' => TRUE, 'clear' => TRUE)); + } + + $global_targeting = array(); + foreach ($tag->global_targeting as $target) { + $global_targeting[$target['target']] = token_replace($target['value'], _dfp_prepare_tokens($tag), array('sanitize' => TRUE, 'clear' => TRUE)); + } + + // Give preference to tag specific targeting values + $targeting = $targeting + $global_targeting; + + $to_json = array('targeting' => $targeting); + $variables['amp_ad_json'] = drupal_json_encode($to_json); + } } - - // Give preference to tag specific targeting values - $targeting = $targeting + $global_targeting; - - $to_json = array('targeting' => $targeting); - $variables['amp_ad_json'] = drupal_json_encode($to_json); } /**