diff --git a/sites/all/modules/metatag/LICENSE.txt b/sites/all/modules/metatag/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1 --- /dev/null +++ b/sites/all/modules/metatag/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/metatag/arrow-down.png b/sites/all/modules/metatag/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..dbd52a3b50ecd2251bd426fcba48afc1a2a9d7e6 Binary files /dev/null and b/sites/all/modules/metatag/arrow-down.png differ diff --git a/sites/all/modules/metatag/arrow-right.png b/sites/all/modules/metatag/arrow-right.png new file mode 100644 index 0000000000000000000000000000000000000000..e14dbaed5a9378006c4696f6169ece2492e2a88a Binary files /dev/null and b/sites/all/modules/metatag/arrow-right.png differ diff --git a/sites/all/modules/metatag/metatag.admin.css b/sites/all/modules/metatag/metatag.admin.css new file mode 100644 index 0000000000000000000000000000000000000000..b7767263fca564c62f29bd88c0102d5f166b5400 --- /dev/null +++ b/sites/all/modules/metatag/metatag.admin.css @@ -0,0 +1,82 @@ +div.metatag-config-label { + padding-left: 20px; +} + +div.metatag-config-label > a { + font-weight: bold; +} + +.metatag-config-label.collapsed { + background-image: url('arrow-right.png'); + background-repeat: no-repeat; + background-position: center left; +} + +.metatag-config-label.expanded { + background-image: url('arrow-down.png'); + background-repeat: no-repeat; + background-position: center left; +} + +table.metatag-config-overview > tbody > tr > td:first-child { + width: 60%; +} + +table.metatag-config-overview > tbody > tr > td { + vertical-align: top; +} + +table.metatag-config-overview tbody div.indent { + margin-left: 20px; +} + +table.metatag-config-overview tr.disabled > td:first-child a { + color: #999; +} + +div.metatag-config-details { + color: #666; + margin-left: 20px; +} + +div.metatag-config-details p { + margin: 0.75em 0; +} + +div.metatag-config-details div.inheritance { + font-style: italic; +} + +div.metatag-config-details table.metatag-value-summary { + border: none; + width: auto; + margin: 0.75em 0; +} + +div.metatag-config-details table.metatag-value-summary td { + padding: 0 0.5em 0 0; + color: #666; +} + +div.metatag-config-details table.metatag-value-summary tr, +div.metatag-config-details table.metatag-value-summary tr td:last-child { + background-color: transparent; + border: none; +} + +div.metatag-config-details table.metatag-value-summary tr td:first-child { + font-weight: bold; + padding-right: 2em; +} + +/*div.metatag-config-details ul { + margin-left: 2em; +} + +div.metatag-config-details ul li { + line-height: 105%; +} + +div.metatag-config-details > p { + margin: 0.25em 0; +}*/ diff --git a/sites/all/modules/metatag/metatag.admin.inc b/sites/all/modules/metatag/metatag.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..d7873807b3ff465631179c80fbda711524c0104b --- /dev/null +++ b/sites/all/modules/metatag/metatag.admin.inc @@ -0,0 +1,384 @@ +<?php + +/** + * @file + * Administration page callbacks for the metatag module. + */ + +function _metatag_config_sort($a, $b) { + $return = NULL; + $a_contexts = explode(':', $a->instance); + $b_contexts = explode(':', $b->instance); + for ($i = 0; $i < max(count($a_contexts), count($b_contexts)); $i++) { + $a_context = isset($a_contexts[$i]) ? $a_contexts[$i] : ''; + $b_context = isset($b_contexts[$i]) ? $b_contexts[$i] : ''; + if ($a_context == $b_context) { + continue; + } + elseif ($a_context == 'global') { + $return = -1; + } + elseif ($a_context == '') { + $return = -1; + } + else { + $return = strcmp($a_context, $b_context); + } + } + return $return; +} + +function _metatag_config_overview_indent($text, $instance) { + $parents = metatag_config_get_parent_instances($instance); + array_shift($parents); + + // Add indentation to the leading cell. + if (!empty($parents)) { + $prefix = array_fill(0, count($parents), '<div class="indent">'); + $suffix = array_fill(0, count($parents), '</div>'); + $text = implode('', $prefix) . $text . implode('', $suffix); + } + + return $text; +} + +function metatag_config_overview() { + ctools_include('export'); + + $metatags = metatag_get_info('tags'); + + $configs = ctools_export_crud_load_all('metatag_config'); + ksort($configs); + //uasort($configs, '_metatag_config_sort'); + + $rows = array(); + foreach ($configs as $config) { + $row = array(); + + // Style disabled configurations differently. + if (!empty($config->disabled)) { + $row['class'][] = 'disabled'; + } + + $details = '<div class="metatag-config-label collapsed"><a href="#" class="toggle-details">' . check_plain(metatag_config_instance_label($config->instance)) . '</a></div>'; + $details .= '<div class="metatag-config-details js-hide">'; + + $inherits = array(); + $parents = metatag_config_get_parent_instances($config->instance); + array_shift($parents); + foreach (array_reverse($parents) as $parent) { + if (!isset($configs[$parent])) { + $rows[$parent] = array( + _metatag_config_overview_indent('<div class="metatag-config-label">' . check_plain(metatag_config_instance_label($parent)) . '</div>', $parent), + '', + ); + } + else { + $inherits[$parent] = metatag_config_instance_label($parent); + if (!empty($configs[$parent]->disabled)) { + $inherits[$parent] .= ' ' . t('(disabled)'); + } + } + } + + // Show how this config inherits from its parents. + if (!empty($inherits)) { + $details .= '<div class="inheritance"><p>' . t('Inherits meta tags from: @parents', array('@parents' => implode(', ', $inherits))) . '</p></div>'; + } + + // Add a summary of the configuration's defaults. + $summary = array(); + foreach ($config->config as $metatag => $data) { + $summary[] = array( + check_plain($metatags[$metatag]['label']) . ':', + check_plain(metatag_get_value($metatag, $data, array('raw' => TRUE))), + ); + } + if (!empty($summary)) { + $details .= theme('table', array( + 'rows' => $summary, + 'attributes' => array('class' => array('metatag-value-summary')), + )); + } + else { + $details .= '<p class="warning">No overridden default meta tags</p>'; + $row['class'][] = 'warning'; + } + + // Close the details div + $details .= '</div>'; + + // Add indentation to the leading cell based on how many parents the config has. + $details = _metatag_config_overview_indent($details, $config->instance); + + $row['data']['details'] = $details; + + $operations = array(); + if (metatag_config_access('disable', $config)) { + $operations['edit'] = array( + 'title' => ($config->export_type & EXPORT_IN_DATABASE) ? t('Edit') : t('Override'), + 'href' => 'admin/config/search/metatags/config/' . $config->instance, + ); + } + if (metatag_config_access('enable', $config)) { + $operations['enable'] = array( + 'title' => t('Enable'), + 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/enable', + 'query' => array( + 'token' => drupal_get_token('enable-' . $config->instance), + ) + drupal_get_destination(), + ); + } + if (metatag_config_access('disable', $config)) { + $operations['disable'] = array( + 'title' => t('Disable'), + 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/disable', + 'query' => array( + 'token' => drupal_get_token('disable-' . $config->instance), + ) + drupal_get_destination(), + ); + } + if (metatag_config_access('revert', $config)) { + $operations['revert'] = array( + 'title' => t('Revert'), + 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/revert', + ); + } + if (metatag_config_access('delete', $config)) { + $operations['delete'] = array( + 'title' => t('Delete'), + 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/delete', + ); + } + $operations['export'] = array( + 'title' => t('Export'), + 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/export', + ); + $row['data']['operations'] = array( + 'data' => array( + '#theme' => 'links', + '#links' => $operations, + '#attributes' => array('class' => array('links', 'inline')), + ), + ); + + $rows[$config->instance] = $row; + } + + $build['config_table'] = array( + '#theme' => 'table', + '#header' => array( + 'type' => t('Type'), + 'operations' => t('Operations'), + ), + '#rows' => $rows, + '#empty' => t('No meta tag defaults available yet.'), + '#caption' => '<div class="js-show">' . t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.') . '</div>', + '#attributes' => array( + 'class' => array('metatag-config-overview'), + ), + '#attached' => array( + 'js' => array( + drupal_get_path('module', 'metatag') . '/metatag.admin.js', + ), + 'css' => array( + drupal_get_path('module', 'metatag') . '/metatag.admin.css', + ), + ), + ); + + return $build; +} + +/** + * Build an FAPI #options array for the instance select field. + */ +function _metatag_config_instance_get_available_options() { + $options = array(); + $instances = metatag_config_instance_info(); + + foreach ($instances as $instance => $instance_info) { + if (metatag_config_load($instance)) { + continue; + } + $parents = metatag_config_get_parent_instances($instance, FALSE); + array_shift($parents); + if (!empty($parents)) { + $parent = reset($parents); + $parent_label = isset($instances[$parent]['label']) ? $instances[$parent]['label'] : t('Unknown'); + if (!isset($options[$parent_label])) { + $options[$parent_label] = array(); + if (!metatag_config_load($parent)) { + $options[$parent_label][$parent] = t('All'); + } + } + $options[$parent_label][$instance] = $instance_info['label']; + unset($options[$parent]); + } + else { + $options[$instance] = $instance_info['label']; + } + } + + return $options; +} + +function metatag_config_add_form($form, &$form_state) { + $form['instance'] = array( + '#type' => 'select', + '#title' => t('Type'), + '#description' => t('Select the type of default meta tags you would like to add.'), + '#options' => _metatag_config_instance_get_available_options(), + '#required' => TRUE, + ); + $form['config'] = array( + '#type' => 'value', + '#value' => array(), + ); + + $form['actions']['#type'] = 'actions'; + $form['actions']['save'] = array( + '#type' => 'submit', + '#value' => t('Add and configure'), + ); + $form['actions']['cancel'] = array( + '#type' => 'link', + '#title' => t('Cancel'), + '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags', + ); + + return $form; +} + +function metatag_config_add_form_submit($form, &$form_state) { + form_state_values_clean($form_state); + $config = (object) $form_state['values']; + metatag_config_save($config); + $form_state['redirect'] = 'admin/config/search/metatags/config/' . $config->instance; +} + +function metatag_config_edit_form($form, &$form_state, $config) { + $form['cid'] = array( + '#type' => 'value', + '#value' => !empty($config->cid) ? $config->cid : NULL, + ); + $form['instance'] = array( + '#type' => 'value', + '#value' => $config->instance, + ); + + $contexts = explode(':', $config->instance); + $options['context'] = $contexts[0]; + if ($contexts[0] != 'global') { + $options['token types'] = array(token_get_entity_mapping('entity', $contexts[0])); + } + + // Ensure that this configuration is properly compared to its parent 'default' + // configuration values. + if (count($contexts) > 1) { + // If the config is something like 'node:article' or 'taxonomy_term:tags' + // then the parent default config is 'node' or 'taxonomy_term'. + $default_instance = $contexts; + array_pop($default_instance); + $default_instance = implode(':', $default_instance); + $options['defaults'] = metatag_config_load_with_defaults($default_instance); + } + elseif ($contexts[0] != 'global') { + // If the config is something like 'node' or 'taxonomy_term' then the + // parent default config is 'global'. + $options['defaults'] = metatag_config_load_with_defaults('global'); + } + else { + // If the config is 'global' than there are no parent defaults. + $options['defaults'] = array(); + } + + metatag_metatags_form($form, $config->instance, $config->config, $options); + $form['metatags']['#type'] = 'container'; + + $form['actions']['#type'] = 'actions'; + $form['actions']['save'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + $form['actions']['cancel'] = array( + '#type' => 'link', + '#title' => t('Cancel'), + '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags', + ); + + $form['#submit'][] = 'metatag_config_edit_form_submit'; + return $form; +} + +function metatag_config_edit_form_submit($form, &$form_state) { + // Build the configuration object and save it. + form_state_values_clean($form_state); + $config = (object) $form_state['values']; + // @todo Consider renaming the config field from 'config' to 'metatags' + $config->config = $config->metatags; + unset($config->metatags); + metatag_config_save($config); + + $label = metatag_config_instance_label($config->instance); + drupal_set_message(t('The meta tag defaults for @label have been saved.', array('@label' => $label))); + + $form_state['redirect'] = 'admin/config/search/metatags'; +} + +function metatag_config_enable($config) { + if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'enable-' . $config->instance)) { + return MENU_ACCESS_DENIED; + } + + ctools_export_crud_enable('metatag_config', $config); + + $label = metatag_config_instance_label($config->instance); + drupal_set_message(t('The meta tag defaults for @label have been enabled.', array('@label' => $label))); + drupal_goto(); +} + +function metatag_config_disable($config) { + if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'disable-' . $config->instance)) { + return MENU_ACCESS_DENIED; + } + + ctools_export_crud_disable('metatag_config', $config); + + $label = metatag_config_instance_label($config->instance); + drupal_set_message(t('The meta tag defaults for @label have been disabed.', array('@label' => $label))); + drupal_goto(); +} + +function metatag_config_delete_form($form, &$form_state, $config) { + $form['cid'] = array('#type' => 'value', '#value' => $config->cid); + $form['instance'] = array('#type' => 'value', '#value' => $config->instance); + + $label = metatag_config_instance_label($config->instance); + $delete = metatag_config_access('delete', $config); + $title = $delete ? t('Are you sure you want to delete the meta tag defaults for @label?', array('@label' => $label)) : t('Are you sure you want to revert the meta tag defaults for @label?', array('@label' => $label)); + + return confirm_form( + $form, + $title, + 'admin/config/search/metatags', + t('This action cannot be undone.') + ); +} + +function metatag_config_delete_form_submit($form, &$form_state) { + $config = metatag_config_load($form_state['values']['instance']); + metatag_config_delete($config->instance); + + $label = metatag_config_instance_label($config->instance); + $delete = metatag_config_access('delete', $config); + $title = $delete ? t('The meta tag defaults for @label have been deleted.', array('@label' => $label)) : t('The meta tag defaults for @label have been reverted.', array('@label' => $label)); + drupal_set_message($title); + + $form_state['redirect'] = 'admin/config/search/metatags'; +} + +function metatag_config_export_form($config) { + ctools_include('export'); + return drupal_get_form('ctools_export_form', ctools_export_crud_export('metatag_config', $config), t('Export')); +} diff --git a/sites/all/modules/metatag/metatag.admin.js b/sites/all/modules/metatag/metatag.admin.js new file mode 100644 index 0000000000000000000000000000000000000000..f278226f686bdce97874cec2d972ca200885b988 --- /dev/null +++ b/sites/all/modules/metatag/metatag.admin.js @@ -0,0 +1,30 @@ +(function ($) { + +Drupal.behaviors.metatagUIConfigListing = { + attach: function (context) { + // Hide elements to be visible if JavaScript is enabled. + $('.js-show').show(); + + // Show or hide the summary + $('table.metatag-config-overview a.toggle-details', context).click(function() { + $(this).parent('div').siblings('div.metatag-config-details').each(function() { + if ($(this).hasClass('js-hide')) { + $(this).slideDown('slow').removeClass('js-hide'); + } + else { + $(this).slideUp('slow').addClass('js-hide'); + } + }); + + // Change the expanded or collapsed state of the instance label. + if ($(this).parent('div').hasClass('collapsed')) { + $(this).parent('div').removeClass('collapsed').addClass('expanded'); + } + else { + $(this).parent('div').removeClass('expanded').addClass('collapsed'); + } + }); + } +} + +})(jQuery); diff --git a/sites/all/modules/metatag/metatag.api.php b/sites/all/modules/metatag/metatag.api.php new file mode 100644 index 0000000000000000000000000000000000000000..b1245a0355d86abd6b95987b8e96c16fe8400f33 --- /dev/null +++ b/sites/all/modules/metatag/metatag.api.php @@ -0,0 +1,5 @@ +<?php +/** + * @file + * API documentation for the Metatag module. + */ diff --git a/sites/all/modules/metatag/metatag.inc b/sites/all/modules/metatag/metatag.inc new file mode 100644 index 0000000000000000000000000000000000000000..f079d2971e999cb78a3efc71a0a99daccf712970 --- /dev/null +++ b/sites/all/modules/metatag/metatag.inc @@ -0,0 +1,189 @@ +<?php + +interface DrupalMetaTagInterface { + + /** + * Constructor + * + * @param array $info + * The information about the meta tag from metatag_get_info(). + */ + function __construct(array $info, array $data = array()); + + function getForm(); + + //function validateForm(); + + //function processForm(); + + function getValue(); + + function getElement(); +} + +class DrupalDefaultMetaTag implements DrupalMetaTagInterface { + + protected $info; + protected $data = array('value' => ''); + + function __construct(array $info, array $data = NULL) { + $this->info = $info; + if (isset($data)) { + $this->data = $data; + } + } + + public function getForm(array $options = array()) { + return array(); + } + + public function getValue(array $options = array()) { + return $this->data['value']; + } + + public function getElement(array $options = array()) { + $element = isset($this->info['element']) ? $this->info['element'] : array(); + + $value = $this->getValue($options); + if (strlen($value) === 0) { + return array(); + } + + $element += array( + '#theme' => 'metatag', + '#tag' => 'meta', + '#id' => 'metatag_' . $this->info['name'], + '#name' => $this->info['name'], + '#value' => $value, + ); + + // Add header information if desired. + if (!empty($this->info['header'])) { + $element['#attached']['drupal_add_http_header'][] = array($this->info['header'], $value); + } + + return array( + '#attached' => array('drupal_add_html_head' => array(array($element, $element['#id']))), + ); + return $element; + } +} + +/** + * Text-based meta tag controller. + */ +class DrupalTextMetaTag extends DrupalDefaultMetaTag { + + public function getForm(array $options = array()) { + $options += array( + 'token types' => array(), + ); + + $form['value'] = isset($this->info['form']) ? $this->info['form'] : array(); + + $form['value'] += array( + '#type' => 'textfield', + '#title' => $this->info['label'], + '#description' => !empty($this->info['description']) ? $this->info['description'] : '', + '#default_value' => isset($this->data['value']) ? $this->data['value'] : '', + '#element_validate' => array('token_element_validate'), + '#token_types' => $options['token types'], + '#maxlength' => 255, + ); + + return $form; + } + + public function getValue(array $options = array()) { + $options += array( + 'token data' => array(), + 'clear' => TRUE, + 'sanitize' => FALSE, + 'raw' => FALSE, + ); + + $value = $this->data['value']; + if (empty($options['raw'])) { + $value = token_replace($value, $options['token data'], $options); + } + $value = strip_tags(decode_entities($value)); + $value = trim($value); + return $value; + } +} + +/** + * Link type meta tag controller. + */ +class DrupalLinkMetaTag extends DrupalTextMetaTag { + + public function getElement(array $options = array()) { + $element = isset($this->info['element']) ? $this->info['element'] : array(); + + $value = $this->getValue($options); + if (strlen($value) === 0) { + return array(); + } + + $element += array( + '#theme' => 'metatag_link_rel', + '#tag' => 'link', + '#id' => 'metatag_' . $this->info['name'], + '#name' => $this->info['name'], + '#value' => $value, + ); + + if (!isset($this->info['header']) || !empty($this->info['header'])) { + // Also send the generator in the HTTP header. + // @todo This does not support 'rev' or alternate link headers. + $element['#attached']['drupal_add_http_header'][] = array('Link', '<' . check_plain($value) . '>;' . drupal_http_header_attributes(array('rel' => $element['#name'])), TRUE); + } + + return array( + '#attached' => array('drupal_add_html_head' => array(array($element, $element['#id']))), + ); + return $element; + } +} + +/** + * Title meta tag controller. + * + * This extends DrupalTextMetaTag as we need to alter variables in + * template_preprocess_html() rather output a normal meta tag. + */ +class DrupalTitleMetaTag extends DrupalTextMetaTag { + + public function getElement(array $options = array()) { + $element = array(); + $value = check_plain($this->getValue($options)); + $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'head_title', $value); + $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'head_array', array('title' => $value)); + return $element; + } +} + +/** + * Multiple value meta tag controller. + */ +class DrupalListMetaTag extends DrupalDefaultMetaTag { + + public function getForm(array $options = array()) { + $form['value'] = isset($this->info['form']) ? $this->info['form'] : array(); + + $form['value'] += array( + '#type' => 'checkboxes', + '#title' => $this->info['label'], + '#description' => !empty($this->info['description']) ? $this->info['description'] : '', + '#default_value' => isset($this->data['value']) ? $this->data['value'] : array(), + ); + + return $form; + } + + public function getValue(array $options = array()) { + $values = array_keys(array_filter($this->data['value'])); + sort($values); + return implode(', ', $values); + } +} diff --git a/sites/all/modules/metatag/metatag.info b/sites/all/modules/metatag/metatag.info new file mode 100644 index 0000000000000000000000000000000000000000..0addb2e115d62b86a279c9850e6af4659a6a788d --- /dev/null +++ b/sites/all/modules/metatag/metatag.info @@ -0,0 +1,17 @@ +name = Meta tags +description = "Adds support and an API to implement meta tags." +package = Meta tags +core = 7.x +dependencies[] = token +dependencies[] = ctools +configure = admin/config/search/metatags + +files[] = metatag.inc +files[] = metatag.test + +; Information added by drupal.org packaging script on 2012-07-13 +version = "7.x-1.0-alpha6+1-dev" +core = "7.x" +project = "metatag" +datestamp = "1342182783" + diff --git a/sites/all/modules/metatag/metatag.install b/sites/all/modules/metatag/metatag.install new file mode 100644 index 0000000000000000000000000000000000000000..47518f91205c34086fc9f3b5437dfa2740c35762 --- /dev/null +++ b/sites/all/modules/metatag/metatag.install @@ -0,0 +1,112 @@ +<?php + +/** + * @file + * Install, update, and uninstall functions for the metatag module. + */ + +/** + * Implements hook_schema(). + */ +function metatag_schema() { + $schema['metatag_config'] = array( + 'description' => 'Storage of meta tag configuration and defaults.', + 'export' => array( + 'key' => 'instance', + 'key name' => 'Instance', + 'primary key' => 'cid', + 'identifier' => 'config', + 'default hook' => 'metatag_config_default', + 'api' => array( + 'owner' => 'metatag', + 'api' => 'metatag', + 'minimum_version' => 1, + 'current_version' => 1, + ), + 'cache defaults' => TRUE, + 'default cache bin' => 'cache_metatag', + ), + 'fields' => array( + 'cid' => array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The primary identifier for a metatag configuration set.', + ), + 'instance' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The machine-name of the configuration, typically entity-type:bundle.', + ), + 'config' => array( + 'type' => 'blob', + 'size' => 'big', + 'not null' => TRUE, + 'serialize' => TRUE, + 'description' => 'Serialized data containing the meta tag configuration.', + 'translatable' => TRUE, + ), + ), + 'primary key' => array('cid'), + 'unique keys' => array( + 'instance' => array('instance'), + ), + ); + + $schema['metatag'] = array( + 'fields' => array( + 'entity_type' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The entity type this data is attached to', + ), + 'entity_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The entity id this data is attached to', + ), + // @todo Enable revisionable meta tags. + 'data' => array( + 'type' => 'blob', + 'size' => 'big', + 'not null' => TRUE, + 'serialize' => TRUE, + ), + ), + 'primary key' => array('entity_type', 'entity_id'), + ); + + $schema['cache_metatag'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_metatag']['description'] = t('Cache table for the generated meta tag output.'); + + return $schema; +} + +/** + * Disable the deprecated metatag_ui module which has been merged into metatag. + */ +function metatag_update_7000() { + if (module_exists('metatag_ui')) { + module_disable(array('metatag_ui'), FALSE); + drupal_uninstall_modules(array('metatag_ui'), FALSE); + } +} + +/** + * Fix the {metatag_config}.cid column cannot be NULL. + */ +function metatag_update_7001() { + $field = array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The primary identifier for a metatag configuration set.', + ); + db_change_field('metatag_config', 'cid', 'cid', $field); +} diff --git a/sites/all/modules/metatag/metatag.metatag.inc b/sites/all/modules/metatag/metatag.metatag.inc new file mode 100644 index 0000000000000000000000000000000000000000..51f0c99e5521d7ff4e32b388411b7fdc33ac18ea --- /dev/null +++ b/sites/all/modules/metatag/metatag.metatag.inc @@ -0,0 +1,177 @@ +<?php + +/** + * Implements hook_metatag_config_default(). + */ +function metatag_metatag_config_default() { + $configs = array(); + + $config = new stdClass(); + $config->instance = 'global'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'title' => array('value' => '[current-page:title] | [site:name]'), + 'generator' => array('value' => 'Drupal 7 (http://drupal.org)'), + ); + $configs[$config->instance] = $config; + + $config = new stdClass(); + $config->instance = 'global:frontpage'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'title' => array('value' => variable_get('site_slogan') ? '[site:name] | [site:slogan]' : '[site:name]'), + 'canonical' => array('value' => '[site:url]'), + ); + $configs[$config->instance] = $config; + + $config = new stdClass(); + $config->instance = 'node'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'title' => array('value' => '[node:title] | [site:name]'), + 'description' => array('value' => '[node:summary]'), + ); + $configs[$config->instance] = $config; + + if (module_exists('taxonomy')) { + $config = new stdClass(); + $config->instance = 'taxonomy_term'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'title' => array('value' => '[term:name] | [site:name]'), + 'description' => array('value' => '[term:description]'), + ); + $configs[$config->instance] = $config; + } + + $config = new stdClass(); + $config->instance = 'user'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'title' => array('value' => '[user:name] | [site:name]'), + ); + $configs[$config->instance] = $config; + + return $configs; +} + +/** + * Implements hook_metatag_config_instance_info(). + */ +function metatag_metatag_config_instance_info() { + $info['global'] = array('label' => t('Global')); + $info['global:frontpage'] = array('label' => t('Front page')); + // @todo The 403 and 404 meta tag contexts are disabled until they can be properly implemented. + //$info['global:403'] = array('label' => t('403 page not found')); + //$info['global:404'] = array('label' => t('404 page not found')); + + // Add instance information for entities. + $entity_types = entity_get_info(); + foreach ($entity_types as $entity_type => $entity_info) { + if (metatag_entity_supports_metatags($entity_type)) { + $info[$entity_type] = array('label' => $entity_info['label']); + foreach ($entity_info['bundles'] as $bundle => $bundle_info) { + if (count($entity_info['bundles'] == 1) && $bundle == $entity_type) { + // Skip default bundles (entities that do not really have bundles). + continue; + } + if (metatag_entity_supports_metatags($entity_type, $bundle)) { + $info[$entity_type . ':' . $bundle] = array('label' => $bundle_info['label']); + } + } + } + } + + return $info; +} + +/** + * Implements hook_metatag_info(). + */ +function metatag_metatag_info() { + $info['groups']['advanced'] = array( + 'label' => t('Advanced'), + 'form' => array( + '#weight' => 90, + ), + ); + + $info['tags']['description'] = array( + 'label' => t('Description'), + 'description' => t("A brief and concise summary of the page's content, preferrably 150 characters or less. The description meta tag may be used by search engines to display a snippet about the page in search results."), + 'class' => 'DrupalTextMetaTag', + 'form' => array( + '#type' => 'textarea', + '#rows' => 2, + '#wysiwyg' => FALSE, + ), + ); + $info['tags']['keywords'] = array( + 'label' => t('Keywords'), + 'description' => t("A comma-separated list of keywords about the page. This meta tag is <em>not</em> supported by most search engines."), + 'class' => 'DrupalTextMetaTag', + ); + $info['tags']['title'] = array( + 'label' => t('Title'), + 'description' => t("The text to display in the title bar of a visitor's web browser when they view this page. This meta tag may also be used as the title of the page when a visitor bookmarks or favorites this page."), + 'class' => 'DrupalTitleMetaTag', + ); + + // More advanced meta tags. + $info['tags']['robots'] = array( + 'label' => t('Robots'), + 'description' => t("Provides search engines with specific directions for what to do when this page is indexed."), + 'class' => 'DrupalListMetaTag', + 'form' => array( + '#options' => array( + 'noindex' => t('Prevent search engines from indexing this page.'), + 'nofollow' => t('Prevent search engines from following links on this page.'), + 'noarchive' => t('Prevent a cached copy of this page from being available in the search results.'), + 'nosnippet' => t('Prevents a description from appearing below the page in the search results, as well as prevents caching of the page.'), + 'noodp' => t('Blocks the <a href="@odp-url">Open Directory Project</a> description of the page from being used in the description that appears below the page in the search results.', array('@odp-url' => 'http://www.dmoz.org/')), + ), + ), + 'group' => 'advanced', + ); + $info['tags']['generator'] = array( + 'label' => t('Generator'), + 'description' => t("Describes the name and version number of the software or publishing tool used to create the page."), + 'class' => 'DrupalTextMetaTag', + 'header' => 'X-Generator', + 'context' => array('global'), + 'group' => 'advanced', + ); + $info['tags']['copyright'] = array( + 'label' => t('Copyright'), + 'description' => t("Details a copyright, trademark, patent, or other information that pertains to intellectual property about this page. Note that this will not automatically protect your site's content or your intellectual property."), + 'class' => 'DrupalTextMetaTag', + 'group' => 'advanced', + ); + + // Link tags. + $info['tags']['canonical'] = array( + 'label' => t('Canonical URL'), + 'description' => t("Tells search engines where the preferred location or URL is for this page to help eliminate self-created duplicate content for search engines."), + 'class' => 'DrupalLinkMetaTag', + 'group' => 'advanced', + ); + $info['tags']['shortlink'] = array( + 'label' => t('Shortlink URL'), + 'description' => '', + 'class' => 'DrupalLinkMetaTag', + 'group' => 'advanced', + ); + $info['tags']['publisher'] = array( + 'label' => t('Publisher URL'), + 'description' => '', + 'class' => 'DrupalLinkMetaTag', + 'group' => 'advanced', + ); + + return $info; +} diff --git a/sites/all/modules/metatag/metatag.module b/sites/all/modules/metatag/metatag.module new file mode 100644 index 0000000000000000000000000000000000000000..9899f5e4e96c08864f818981d2b99839cdc65d18 --- /dev/null +++ b/sites/all/modules/metatag/metatag.module @@ -0,0 +1,1145 @@ +<?php + +/** + * @todo Add revisionable support for metatag data. + * @todo Add multilingual support for metatag data - is this even needed? + */ + +/** + * Implements hook_theme(). + */ +function metatag_theme() { + $info['metatag'] = array( + 'render element' => 'element', + 'file' => 'metatag.theme.inc', + ); + $info['metatag_http_equiv'] = array( + 'render element' => 'element', + 'file' => 'metatag.theme.inc', + ); + $info['metatag_link_rel'] = array( + 'render element' => 'element', + 'file' => 'metatag.theme.inc', + ); + $info['metatag_link_rev'] = array( + 'render element' => 'element', + 'file' => 'metatag.theme.inc', + ); + + return $info; +} + +/** + * Implements hook_ctools_plugin_api(). + */ +function metatag_ctools_plugin_api($owner, $api) { + if ($owner == 'metatag' && $api == 'metatag') { + return array('version' => 1); + } +} + +/** + * Implements hook_hook_info(). + */ +function metatag_hook_info() { + $hooks = array( + 'metatag_info', + 'metatag_info_alter', + 'metatag_config_instance_info', + 'metatag_config_instance_info_alter', + 'metatag_config_load', + 'metatag_config_presave', + 'metatag_config_insert', + 'metatag_config_update', + 'metatag_config_delete', + 'metatag_load', + 'metatag_insert', + 'metatag_update', + 'metatag_delete', + 'metatag_alter', + 'metatag_config_default', + 'metatag_config_default_alter', + 'metatag_api', + ); + + return array_fill_keys($hooks, array('group' => 'metatag')); +} + +/** + * Implements hook_permisson(). + */ +function metatag_permission() { + $permissions['administer meta tags'] = array( + 'title' => t('Administer meta tags.'), + 'restrict access' => TRUE, + ); + $permissions['edit meta tags'] = array( + 'title' => t('Edit meta tags.'), + ); + return $permissions; +} + +/** + * Implements hook_menu(). + */ +function metatag_menu() { + $items['admin/config/search/metatags'] = array( + 'title' => 'Meta tags', + 'description' => 'Configure meta tag defaults.', + 'page callback' => 'metatag_config_overview', + 'access arguments' => array('administer meta tags'), + 'file' => 'metatag.admin.inc', + ); + $items['admin/config/search/metatags/config'] = array( + 'title' => 'Defaults', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['admin/config/search/metatags/config/add'] = array( + 'title' => 'Add a meta tag default', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('metatag_config_add_form'), + 'access arguments' => array('administer meta tags'), + 'file' => 'metatag.admin.inc', + 'type' => MENU_LOCAL_ACTION, + ); + $items['admin/config/search/metatags/config/%metatag_config'] = array( + 'title callback' => 'metatag_config_title', + 'title arguments' => array(5), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('metatag_config_edit_form', 5), + 'access arguments' => array('administer meta tags'), + 'file' => 'metatag.admin.inc', + ); + $items['admin/config/search/metatags/config/%metatag_config/edit'] = array( + 'title' => 'Edit', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['admin/config/search/metatags/config/%metatag_config/enable'] = array( + 'title' => 'Enable', + 'page callback' => 'metatag_config_enable', + 'page arguments' => array(5), + 'access callback' => 'metatag_config_access', + 'access arguments' => array('enable', 5), + 'file' => 'metatag.admin.inc', + ); + $items['admin/config/search/metatags/config/%metatag_config/disable'] = array( + 'title' => 'Disable', + 'page callback' => 'metatag_config_disable', + 'page arguments' => array(5), + 'access callback' => 'metatag_config_access', + 'access arguments' => array('disable', 5), + 'file' => 'metatag.admin.inc', + ); + $items['admin/config/search/metatags/config/%metatag_config/revert'] = array( + 'title' => 'Revert', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('metatag_config_delete_form', 5), + 'access callback' => 'metatag_config_access', + 'access arguments' => array('revert', 5), + 'file' => 'metatag.admin.inc', + 'type' => MENU_LOCAL_TASK, + ); + $items['admin/config/search/metatags/config/%metatag_config/delete'] = array( + 'title' => 'Delete', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('metatag_config_delete_form', 5), + 'access callback' => 'metatag_config_access', + 'access arguments' => array('delete', 5), + 'file' => 'metatag.admin.inc', + ); + $items['admin/config/search/metatags/config/%metatag_config/export'] = array( + 'title' => 'Export', + 'page callback' => 'metatag_config_export_form', + 'page arguments' => array(5), + 'access arguments' => array('administer meta tags'), + 'file' => 'metatag.admin.inc', + 'type' => MENU_LOCAL_TASK, + 'weight' => 10, + ); + + return $items; +} + +/** + * Implements hook_flush_caches(). + */ +function metatag_flush_caches() { + return array('cache_metatag'); +} + +/** + * Load a metatag configuration record with all the defaults merged in. + * + * For example, given the configuration instance 'node:article', this function + * will load the configuration records for 'node:article', then 'node', and + * then finally 'global', with each attempt using an array merge. + * + * The levels of defaults is arranged by splitting the $instance variable by + * the colon character, and always using a 'global' instance at the end. + */ +function metatag_config_load_with_defaults($instance) { + $defaults = &drupal_static(__FUNCTION__, array()); + + // Check to see if + if (!isset($defaults[$instance])) { + $cid = "config:{$instance}"; + if ($cache = cache_get($cid, 'cache_metatag')) { + $defaults[$instance] = $cache->data; + } + else { + $defaults[$instance] = array(); + $instances = metatag_config_get_parent_instances($instance); + $configs = metatag_config_load_multiple($instances); + foreach ($instances as $key) { + // Ignore disabled configurations. + if (!isset($configs[$key]) || !empty($configs[$key]->disabled)) { + continue; + } + + // Add config to the defaults array. + $defaults[$instance] += $configs[$key]->config; + } + + cache_set($cid, $defaults[$instance], 'cache_metatag'); + } + } + + return $defaults[$instance]; +} + +/** + * Load a metatag configuration record. + */ +function metatag_config_load($instance) { + $results = metatag_config_load_multiple(array($instance)); + return !empty($results[$instance]) ? $results[$instance] : FALSE; +} + +/** + * Load multiple metatag configuration records. + */ +function metatag_config_load_multiple(array $instances) { + ctools_include('export'); + return ctools_export_load_object('metatag_config', 'names', $instances); +} + +/** + * Save a metatag configuration record to the database. + */ +function metatag_config_save($config) { + $config->is_new = empty($config->cid); + + // Allow modules to alter the configuration before it is saved. + module_invoke_all('metatag_config_presave', $config); + + if ($config->is_new) { + drupal_write_record('metatag_config', $config); + module_invoke_all('metatag_config_insert', $config); + } + else { + drupal_write_record('metatag_config', $config, array('cid')); + module_invoke_all('metatag_config_update', $config); + } + + unset($config->is_new); + + // Clear any caches. + metatag_config_cache_clear(); +} + +/** + * Delete a metatag configuration record. + */ +function metatag_config_delete($instance) { + db_delete('metatag_config') + ->condition('instance', $instance) + ->execute(); + + // Clear any caches. + metatag_config_cache_clear(); +} + +/** + * Clear the metatag configuration cache. + */ +function metatag_config_cache_clear() { + cache_clear_all('*', 'cache_metatag', TRUE); + drupal_static_reset('metatag_config_load_with_defaults'); + ctools_include('export'); + ctools_export_load_object_reset('metatag_config'); +} + +function metatag_metatags_load($type, $id) { + $metatags = metatag_metatags_load_multiple($type, array($id)); + return !empty($metatags) ? reset($metatags) : array(); +} + +function metatag_metatags_load_multiple($type, array $ids) { + // Double check entity IDs are numeric thanks to Entity API module. + $ids = array_filter($ids, 'is_numeric'); + if (empty($ids)) { + return array(); + } + + // Also need to check if the metatag table exists since this condition could + // fire before the table has been installed yet. + if (!db_table_exists('metatag')) { + return array(); + } + + $metatags = db_query("SELECT entity_id, data FROM {metatag} WHERE entity_type = :type AND entity_id IN (:ids)", array( + ':type' => $type, + ':ids' => $ids, + ))->fetchAllKeyed(); + $metatags = array_map('unserialize', $metatags); + return $metatags; +} + +function metatag_metatags_save($type, $id, $metatags) { + // Check that $id is numeric because of Entity API and string IDs. + if (!is_numeric($id)) { + return; + } + + // Allow other modules to alter the metatags prior to saving. + foreach (module_implements('metatag_presave') as $module) { + $function = "{$module}_metatag_presave"; + $function($metatags, $type, $id); + } + + if (empty($metatags)) { + // If the data array is empty, there is no data to actually save, so + // just delete the record from the database. + db_delete('metatag') + ->condition('entity_type', $type) + ->condition('entity_id', $id) + ->execute(); + } + else { + // Otherwise save the data for this entity. + db_merge('metatag') + ->key(array( + 'entity_type' => $type, + 'entity_id' => $id, + )) + ->fields(array( + 'data' => serialize($metatags), + )) + ->execute(); + } + + // Clear cached data. + metatag_metatags_cache_clear($type, $id); +} + +function metatag_metatags_delete($type, $id) { + return metatag_metatags_delete_multiple($type, array($id)); +} + +function metatag_metatags_delete_multiple($type, array $ids) { + // Double check entity IDs are numeric thanks to Entity API module. + $ids = array_filter(array_keys($ids, 'is_numeric')); + + if ($metatags = metatag_metatags_load_multiple($type, $ids)) { + $transaction = db_transaction(); + try { + // Let other modules know about the metatags being deleted. + module_invoke_all('metatag_metatags_delete', $type, $ids); + + db_delete('metatag') + ->condition('entity_type', $type) + ->condition('entity_id', $ids, 'IN') + ->execute(); + + // Clear cached data. + metatag_metatags_cache_clear($type, $ids); + } + catch (Exception $e) { + $transaction->rollback(); + watchdog_exception('metatag', $e); + throw $e; + } + } +} + +function metatag_metatags_cache_clear($type, $id = NULL) { + if (empty($id)) { + cache_clear_all("output:$type", 'cache_metatag', TRUE); + } + else { + $ids = (array) $id; + foreach ($ids as $id) { + cache_clear_all("output:$type:$id", 'cache_metatag', TRUE); + } + } +} + +/** + * Implements hook_entity_load(). + */ +function metatag_entity_load($entities, $type) { + $metatags = metatag_metatags_load_multiple($type, array_keys($entities)); + foreach ($entities as $id => $entity) { + $entities[$id]->metatags = isset($metatags[$id]) ? $metatags[$id] : array(); + } +} + +/** + * Implements hook_entity_insert(). + */ +function metatag_entity_insert($entity, $entity_type) { + if (isset($entity->metatags)) { + list($id) = entity_extract_ids($entity_type, $entity); + metatag_metatags_save($entity_type, $id, $entity->metatags); + } +} + +/** + * Implements hook_entity_update(). + */ +function metatag_entity_update($entity, $entity_type) { + list($id) = entity_extract_ids($entity_type, $entity); + + if (isset($entity->metatags)) { + metatag_metatags_save($entity_type, $id, $entity->metatags); + } + else { + // Still ensure the meta tag output is cached. + metatag_metatags_cache_clear($entity_type, $id); + } +} + +/** + * Implements hook_entity_delete(). + */ +function metatag_entity_delete($entity, $entity_type) { + list($id) = entity_extract_ids($entity_type, $entity); + metatag_metatags_delete($entity_type, $id); +} + +/** + * Implements hook_field_attach_delete_revision(). + */ +function metatag_field_attach_delete_revision($entity_type, $entity) { + //list($entity_id, $revision_id) = entity_extract_ids($entity_type, $entity); +} + +/** + * Implements hook_field_attach_view_alter(). + */ +function metatag_field_attach_view_alter(&$output, $context) { + $entity_type = $context['entity_type']; + $entity = $context['entity']; + list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity); + + if (metatag_entity_supports_metatags($entity_type, $bundle) && $context['view_mode'] == 'full' && _metatag_entity_is_page($entity_type, $entity)) { + $cid_parts = array( + //'view_mode' => $context['view_mode'], + 'langcode' => $context['language'], + 'url' => $GLOBALS['base_url'] . '/' . current_path(), + ); + $cid = "output:{$entity_type}:{$entity_id}:" . hash('sha256', serialize($cid_parts)); + + if ($cache = cache_get($cid, 'cache_metatag')) { + $output['metatags'] = $cache->data; + } + else { + $metatags = isset($entity->metatags) ? $entity->metatags : array(); + $instance = "{$entity_type}:{$bundle}"; + + // Build options for meta tag rendering. The context variable already + // contains entity type, entity, view mode, language, etc. + $options = $context; + + // Ensure we actually pass a language object rather than language code. + $languages = language_list(); + if (isset($context['language']) && isset($languages[$context['language']])) { + $options['language'] = $languages[$context['language']]; + } + + // Reload the entity object from cache as it may have been altered by Panels. + $token_type = token_get_entity_mapping('entity', $entity_type); + $entities = entity_load($entity_type, array($entity_id)); + $options['token data'][$token_type] = $entities[$entity_id]; + $options['entity'] = $entities[$entity_id]; + + // Render the metatags and save to the cache. + $output['metatags'] = metatag_metatags_view($instance, $metatags, $options); + cache_set($cid, $output['metatags'], 'cache_metatag'); + } + + // We have to add a '#field_type' property otherwise + // rdf_field_attach_view_alter() freaks out. + $output['metatags']['#field_type'] = NULL; + } +} + +/** + * Build a renderable array of meta tag output. + * + * @param string $instance + * The configuration instance key of the metatags to use, e.g. "node:article". + * @param array $metatags + * An arary of metatag data. + * @param array $options + * (optional) An array of options including the following keys and values: + * - language: A language object. + * - token data: An array of data to pass into token_replace() during + * meta tag value generation. + */ +function metatag_metatags_view($instance, array $metatags = array(), array $options = array()) { + $output = array(); + $metatags += metatag_config_load_with_defaults($instance); + + // Convert language codes to a language object. + if (isset($options['language']) && is_string($options['language'])) { + $languages = language_list(); + $options['language'] = isset($languages[$options['language']]) ? $languages[$options['language']] : NULL; + } + + foreach ($metatags as $metatag => $data) { + if ($metatag_instance = metatag_get_instance($metatag, $data)) { + $output[$metatag] = $metatag_instance->getElement($options); + } + } + + drupal_alter('metatag_metatags_view', $output); + + return $output; +} + +function metatag_metatags_values($instance, array $metatags = array(), array $options = array()) { + $values = array(); + $metatags += metatag_config_load_with_defaults($instance); + + // Convert language codes to a language object. + if (isset($options['language']) && is_string($options['language'])) { + $languages = language_list(); + $options['language'] = isset($languages[$options['language']]) ? $languages[$options['language']] : NULL; + } + + foreach ($metatags as $metatag => $data) { + if ($metatag_instance = metatag_get_instance($metatag, $data)) { + $values[$metatag] = $metatag_instance->getValue($options); + } + } + + return array_filter($values, 'drupal_strlen'); +} + +/** + * Build a FAPI array for editing meta tags. + * + * @param array $form + * The current FAPI array. + * @param string $instance + * The configuration instance key of the metatags to use, e.g. "node:article". + * @param array $metatags + * An arary of metatag data. + * @param array $options + * (optional) An array of options including the following keys and values: + * - token types: An array of token types to be passed to theme_token_tree(). + */ +function metatag_metatags_form(array &$form, $instance, array $metatags = array(), array $options = array()) { + $info = metatag_get_info(); + if (empty($info['tags'])) { + return; + } + + // Merge in the default options. + $options += array( + 'token types' => array(), + 'defaults' => metatag_config_load_with_defaults($instance), + ); + + $form['metatags'] = array( + '#type' => 'fieldset', + '#title' => t('Meta tags'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#tree' => TRUE, + '#access' => user_access('edit meta tags') || user_access('administer meta tags'), + '#weight' => 10, + '#attributes' => array( + 'class' => array('metatags-form'), + ), + '#metatag_defaults' => $options['defaults'], + ); + + // Only support vertical tabs if there is a vertical tab element. + foreach (element_children($form) as $key) { + if (isset($form[$key]['#type']) && $form[$key]['#type'] == 'vertical_tabs') { + $form['metatags']['#group'] = $key; + $form['metatags']['#attached']['js']['vertical-tabs'] = drupal_get_path('module', 'metatag') . '/metatag.vertical-tabs.js'; + break; + } + } + + // Merge in the default meta tag configurations. + $metatags += $options['defaults']; + + // Build the form for each metatag. + foreach ($info['tags'] as $metatag => $metatag_info) { + // @todo Replace context matching with hook_metatag_access(). + if (isset($options['context']) && isset($metatag_info['context'])) { + if (!in_array($options['context'], $metatag_info['context'])) { + continue; + } + } + + $metatag_instance = metatag_get_instance($metatag, isset($metatags[$metatag]) ? $metatags[$metatag] : array()); + if (empty($metatag_instance)) { + continue; + } + + // Get the form element from the meta tag class. + $metatag_form = $metatag_instance->getForm($options); + + // Add a default value form element. + if (isset($options['defaults'][$metatag]['value'])) { + $metatag_form['default'] = array( + '#type' => 'hidden', + '#value' => $options['defaults'][$metatag]['value'], + ); + } + + if (!empty($metatag_info['group'])) { + $group_key = $metatag_info['group']; + if (isset($info['groups'][$group_key]['label']) && !isset($form['metatags'][$group_key])) { + $group = $info['groups'][$group_key] + array('form' => array(), 'description' => NULL); + $form['metatags'][$group_key] = $group['form'] + array( + '#type' => 'fieldset', + '#title' => check_plain($group['label']), + '#description' => filter_xss($group['description']), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + } + $form['metatags'][$group_key][$metatag] = $metatag_form + array('#parents' => array('metatags', $metatag)); + } + else { + $form['metatags'][$metatag] = $metatag_form; + } + } + + // Show the list of available tokens. + $form['metatags']['tokens'] = array( + '#theme' => 'token_tree', + '#token_types' => $options['token types'], + '#weight' => 100, + ); + + // Add a submit handler to compare the submitted values against the deafult + // values. + $form += array('#submit' => array()); + array_unshift($form['#submit'], 'metatag_metatags_form_submit'); +} + +/** + * Form submit handler; unset meta tag values that equal their default values. + */ +function metatag_metatags_form_submit($form, &$form_state) { + $defaults = $form['metatags']['#metatag_defaults']; + $values = &$form_state['values']['metatags']; + metatag_filter_values_from_defaults($values, $defaults); +} + +/** + * Implements hook_field_extra_fields(). + */ +function metatag_field_extra_fields() { + $extra = array(); + foreach (entity_get_info() as $entity_type => $entity_info) { + foreach (array_keys($entity_info['bundles']) as $bundle) { + if (metatag_entity_supports_metatags($entity_type, $bundle)) { + $extra[$entity_type][$bundle]['form']['metatags'] = array( + 'label' => t('Meta tags'), + 'description' => t('Meta tag module form elements.'), + 'weight' => 10, + ); + } + } + } + return $extra; +} + +function metatag_entity_supports_metatags($entity_type = NULL, $bundle = NULL) { + $types = &drupal_static(__FUNCTION__); + + if (!isset($types)) { + $types = array(); + foreach (entity_get_info() as $entity_type_key => $entity_info) { + if (!isset($entity_info['metatags'])) { + // By default allow entities that have fields and have paths. + $entity_info['metatags'] = !empty($entity_info['uri callback']) && !empty($entity_info['fieldable']); + } + if (empty($entity_info['metatags'])) { + $types[$entity_type_key] = FALSE; + continue; + } + $types[$entity_type_key] = array(); + foreach ($entity_info['bundles'] as $bundle_key => $bundle_info) { + $types[$entity_type_key][$bundle_key] = !isset($bundle_info['metatags']) || !empty($bundle_info['metatags']); + } + } + } + + if (isset($entity_type) && isset($bundle)) { + return isset($types[$entity_type][$bundle]) ? $types[$entity_type][$bundle] : FALSE; + } + elseif (isset($entity_type)) { + return isset($types[$entity_type]) ? ($types[$entity_type] !== FALSE) : FALSE; + } + + return $types; +} + +/** + * Implements hook_entity_info_alter(). + */ +function metatag_entity_info_alter(&$info) { + $defaults['node'] = array( + 'path' => 'node/%node', + ); + $defaults['taxonomy_term'] = array( + 'path' => 'taxonomy/term/%taxonomy_term', + ); + if (module_exists('forum') && ($vid = variable_get('forum_nav_vocabulary', 0)) && $vocabulary = taxonomy_vocabulary_load($vid)) { + $defaults['taxonomy_term']['bundles'][$vocabulary->machine_name]['path'] = 'forum/%taxonomy_term'; + } + $defaults['user'] = array( + 'path' => 'user/%user', + ); + $defaults['comment'] = array( + 'metatags' => FALSE, + ); + + foreach ($defaults as $key => $entity_defaults) { + if (isset($info[$key])) { + $info[$key] = drupal_array_merge_deep($entity_defaults, $info[$key]); + } + } +} + +/** + * Given a path determine if it is an entity default path. + * + * @param $path + * The internal path. The id of the entity should be in the string as '[id]'. + * @return + * An array with the entity type and the loaded entity object. + */ +function metatag_load_entity_from_path($path) { + $entity_paths = &drupal_static(__FUNCTION__); + $result = FALSE; + + if (!isset($entity_paths)) { + $entity_paths = array(); + foreach (entity_get_info() as $entity_type => $entity_info) { + if (isset($entity_info['default path'])) { + $default_path = $entity_info['default path']; + $default_path = preg_quote($default_path, '/'); + $default_path = str_replace('\[id\]', '(\d+)', $default_path); + $entity_paths[$entity_type] = $default_path; + } + } + } + + foreach ($entity_paths as $entity_type => $default_path) { + if (preg_match("/^{$default_path}$/", $path, $matches)) { + if ($entity = entity_load($entity_type, array($matches[1]))) { + $result = array('entity_type' => $entity_type, 'entity' => reset($entity)); + } + break; + } + } + + drupal_alter('metatag_load_entity_from_path', $path, $result); + return $result; +} + +/** + * Implements hook_page_build(). + */ +function metatag_page_build(&$page) { + // For some reason with Overlay enabled we get an empty $page, so just fail + // this case. + if (!isset($page['content'])) { + return; + } + + // Load the metatags render array in before any page content so that more + // more specific meta tags in the page content can override these meta tags. + $page['content'] = array('metatags' => array()) + $page['content']; + if (drupal_is_front_page()) { + $page['content']['metatags']['global:frontpage'] = metatag_metatags_view('global:frontpage', array()); + } + elseif (!path_is_admin(current_path())) { + // Do not output the global metatags when on an administration path. + $page['content']['metatags']['global'] = metatag_metatags_view('global', array()); + } +} + +/** + * Returns whether the current page is the page of the passed in entity. + * + * @param $type + * The entity type; e.g. 'node' or 'user'. + * @param $entity + * The entity object. + * + * @return + * TRUE if the current page is the page of the specified entity, or FALSE + * otherwise. + */ +function _metatag_entity_is_page($type, $entity) { + $uri = entity_uri($type, $entity); + return (!empty($uri) && current_path() == $uri['path']); +} + +/** + * Implements hook_field_attach_rename_bundle(). + */ +function metatag_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) { + $instance_old = $entity_type . ':' . $bundle_old; + $instance_new = $entity_type . ':' . $bundle_new; + if ($config = metatag_config_load($instance_old)) { + $config->instance = $instance_new; + metatag_config_save($config); + metatag_config_delete($instance_old); + } +} + +/** + * Implements hook_field_attach_delete_bundle(). + */ +function metatag_field_attach_delete_bundle($entity_type, $bundle) { + $instance = $entity_type . ':' . $bundle; + metatag_config_delete($instance); +} + +/** + * Implements hook_field_attach_form(). + */ +function metatag_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) { + list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity); + + if (!metatag_entity_supports_metatags($entity_type, $bundle)) { + return; + } + + $instance = "{$entity_type}:{$bundle}"; + + $metatags = isset($entity->metatags) ? $entity->metatags : array(); + $options['token types'] = array(token_get_entity_mapping('entity', $entity_type)); + $options['context'] = $entity_type; + + // @todo Remove metatag_form_alter() when http://drupal.org/node/1284642 is fixed in core. + //metatag_metatags_form($form, $instance, $metatags, $options); + + $form['#metatags'] = array( + 'instance' => $instance, + 'metatags' => $metatags, + 'options' => $options, + ); +} + +/** + * Implements hook_form_alter(). + * + * @todo Remove this when http://drupal.org/node/1284642 is fixed in core. + */ +function metatag_form_alter(&$form, $form_state, $form_id) { + if (!empty($form['#metatags']) && !isset($form['metatags'])) { + extract($form['#metatags']); + metatag_metatags_form($form, $instance, $metatags, $options); + unset($form['#metatags']); + } +} + +/** + * Get the meta tag information array of a meta tag. + * + * @param $metatag + * The meta tag name, e.g. description, for which the info shall be returned, + * or NULL to return an array with info about all meta tags. + */ +function metatag_get_info($type = NULL, $name = NULL) { + // Use the advanced drupal_static() pattern, since this is called very often. + static $drupal_static_fast; + if (!isset($drupal_static_fast)) { + $drupal_static_fast['metatag_info'] = &drupal_static(__FUNCTION__); + } + $info = &$drupal_static_fast['metatag_info']; + + if (!isset($info)) { + // hook_metatag_info() includes translated strings, so each language is cached + // separately. + $cid = 'info:' . $GLOBALS['language']->language; + + if ($cache = cache_get($cid, 'cache_metatag')) { + $info = $cache->data; + } + else { + $info = module_invoke_all('metatag_info'); + $info += array('tags' => array(), 'groups' => array()); + + // Merge in default values. + foreach ($info['tags'] as $key => $data) { + $info['tags'][$key] += array( + // Merge in default values. + 'name' => $key, + 'class' => 'DrupalTextMetaTag', + ); + } + + // Let other modules alter the entity info and then cache it. + drupal_alter('metatag_info', $info); + cache_set($cid, $info, 'cache_metatag'); + } + } + + if (isset($type) && isset($name)) { + return isset($info[$type][$name]) ? $info[$type][$name] : FALSE; + } + elseif (isset($type)) { + return isset($info[$type]) ? $info[$type] : array(); + } + else { + return $info; + } +} + +function metatag_get_instance($metatag, array $data = array()) { + $info = metatag_get_info('tags', $metatag); + if (!empty($info['class']) && class_exists($info['class'])) { + $class = $info['class']; + return new $class($info, $data); + } + else { + trigger_error("Failed to load class {$info['class']} for metatag $metatag.", E_USER_ERROR); + } +} + +/** + * Return the string value of a meta tag. + * + * @param $metatag + * The meta tag string. + * @param $data + * The array of data for the meta tag class instance. + * @param $options + * An optional array of additional options to pass to the getValue() method + * of the meta tag class instance. + * - raw: A boolean if TRUE will not perform token replacement. + * + * @return + * A string value. + */ +function metatag_get_value($metatag, array $data, array $options = array()) { + $value = ''; + if ($metatag_instance = metatag_get_instance($metatag, $data)) { + $value = $metatag_instance->getValue($options); + } + return $value; +} + +/** + * Set a variable to be altered in metatag_preprocess_html(). + * + * @see metatag_get_preprocess_variables() + * @see metatag_preprocess_html() + * @see metatag_preprocess_maintenance_page() + */ +function metatag_set_preprocess_variable($hook, $variable, $value) { + $variables = &drupal_static(__FUNCTION__, array()); + $variables[$hook][$variable] = $value; +} + +/** + * Return an array of variables to be altered in preprocess functions. + * + * @see metatag_set_preprocess_variable() + * @see metatag_preprocess_html() + * @see metatag_preprocess_maintenance_page() + */ +function metatag_get_preprocess_variables($hook) { + $variables = drupal_static('metatag_set_preprocess_variable', array()); + return isset($variables[$hook]) ? $variables[$hook] : array(); +} + +/** + * Implements hook_preprocess_html(). + */ +function metatag_preprocess_html(&$variables) { + foreach (metatag_get_preprocess_variables('html') as $variable => $value) { + $variables[$variable] = $value; + } +} + +/** + * Implements hook_preprocess_maintenance_page(). + */ +function metatag_preprocess_maintenance_page(&$variables) { + foreach (metatag_get_preprocess_variables('html') as $variable => $value) { + $variables[$variable] = $value; + } +} + +/** + * Implements hook_html_head_alter(). + */ +function metatag_html_head_alter(&$elements) { + // Remove duplicate link tags if found. + $metatags = metatag_get_info('tags'); + foreach (array_keys($metatags) as $name) { + if (!isset($elements['metatag_' . $name]) || $elements['metatag_' . $name]['#tag'] != 'link') { + // Only check for link tags added by the metatags module. + continue; + } + foreach (array_keys($elements) as $key) { + if (strpos($key, 'drupal_add_html_head_link:' . $name . ':') === 0) { + unset($elements[$key]); + break; + } + } + } + + // Remove the default generator meta tag. + unset($elements['system_meta_generator']); +} + +function metatag_metatag_get_form($metatag, array $data = array(), array $options = array()) { + $instance = metatag_get_instance($metatag, $data); + return $instance->getForm($options); +} + +function metatag_config_instance_info($instance = NULL) { + global $language; + + $info = &drupal_static(__FUNCTION__); + + // hook_metatag_info() includes translated strings, so each language is cached + // separately. + $cid = 'metatag:config:instance:info:' . $language->language; + + if (!isset($info)) { + if ($cache = cache_get($cid, 'cache_metatag')) { + $info = $cache->data; + } + else { + $info = module_invoke_all('metatag_config_instance_info'); + drupal_alter('metatag_config_instance_info', $info); + cache_set($cid, $info, 'cache_metatag'); + } + } + + if (isset($instance)) { + return isset($info[$instance]) ? $info[$instance] : FALSE; + } + else { + return $info; + } +} + +/** + * Filter out meta tag values that equal the default values. + * + * @todo Use information in $values[$metatag]['default'] rather than a $defaults parameter. + */ +function metatag_filter_values_from_defaults(array &$values, array $defaults = array()) { + foreach ($values as $metatag => $data) { + $default = isset($data['default']) ? $data['default'] : (isset($defaults[$metatag]['value']) ? $defaults[$metatag]['value'] : NULL); + if (isset($default) && isset($data['value']) && $default === $data['value']) { + // Meta tag has a default, and it matches user-submitted value. + unset($values[$metatag]); + } + elseif (!isset($default) && (is_string($data['value']) && !drupal_strlen($data['value']) || (is_array($data['value']) && !array_filter($data['value'])))) { + // Metatag does not have a default, and user did not submit a value. + unset($values[$metatag]); + } + if (isset($values[$metatag]['default'])) { + // Unset the default hidden value. + unset($values[$metatag]['default']); + } + } +} + +/** + * Return all the parents of a given configuration instance. + * + * @param $instance + * A meta tag configuration instance. + * + * @return + * An array of instances starting with the $instance parameter, with the end + * of the array being the global instance. + */ +function metatag_config_get_parent_instances($instance, $include_global = TRUE) { + $parents = array(); + $segments = explode(':', $instance); + while (count($segments) > 0) { + $parents[] = implode(':', $segments); + array_pop($segments); + } + if ($include_global && end($parents) !== 'global') { + $parents[] = 'global'; + } + reset($parents); + return $parents; +} + +/** + * Get the proper label of a configuration instance. + * + * @param $instance + * A meta tag configuration instance. + */ +function metatag_config_instance_label($instance) { + $labels = &drupal_static(__FUNCTION__, array()); + + if (!isset($labels[$instance])) { + $context = metatag_config_instance_info($instance); + $labels[$instance] = isset($context['label']) ? $context['label'] : t('Unknown'); + $parents = metatag_config_get_parent_instances($instance, FALSE); + array_shift($parents); + if (!empty($parents)) { + $labels[$instance] = metatag_config_instance_label(implode(':', $parents)) . ': ' . $labels[$instance]; + } + } + + return $labels[$instance]; +} + +/** + * Title callback for meta tag configuration instances. + */ +function metatag_config_title($config) { + return metatag_config_instance_label($config->instance); +} + +/** + * Access callback for meta tag configuration instances. + */ +function metatag_config_access($op, $config = NULL) { + if (!user_access('administer meta tags')) { + return FALSE; + } + + if ($op == 'enable') { + return !empty($config->disabled); + } + elseif ($op == 'disable') { + return empty($config->disabled); + } + elseif ($op == 'delete') { + return ($config->export_type & EXPORT_IN_DATABASE) && !($config->export_type & EXPORT_IN_CODE); + } + elseif ($op == 'revert') { + return ($config->export_type & EXPORT_IN_DATABASE) && ($config->export_type & EXPORT_IN_CODE); + } + + return FALSE; +} diff --git a/sites/all/modules/metatag/metatag.test b/sites/all/modules/metatag/metatag.test new file mode 100644 index 0000000000000000000000000000000000000000..2133504d79d65fbc857b56b17dee228de49548ac --- /dev/null +++ b/sites/all/modules/metatag/metatag.test @@ -0,0 +1,70 @@ +<?php + +class MetaTagsTestHelper extends DrupalWebTestCase { + function setUp(array $modules = array()) { + $modules[] = 'ctools'; + $modules[] = 'token'; + $modules[] = 'metatag'; + $modules[] = 'metatag_test'; + parent::setUp($modules); + } +} + +class MetaTagsUnitTest extends MetaTagsTestHelper { + public static function getInfo() { + return array( + 'name' => 'Meta tag unit tests', + 'description' => 'Test basic meta tag functionality.', + 'group' => 'Meta tags', + ); + } + + /** + * Test the metatag_config_load_with_defaults() function. + */ + public function testConfigLoadDefaults() { + $defaults = metatag_config_load_with_defaults('test:foo'); + $this->assertEqual($defaults, array( + 'description' => array('value' => 'Test foo description'), + 'title' => array('value' => 'Test altered title'), + 'test:foo' => array('value' => 'foobar'), + 'generator' => array('value' => 'Drupal 7 (http://drupal.org)'), + )); + } + + public function testEntitySupport() { + $test_cases[0] = array('type' => 'node', 'expected' => TRUE); + $test_cases[1] = array('type' => 'node', 'bundle' => 'article', 'expected' => TRUE); + $test_cases[2] = array('type' => 'node', 'bundle' => 'page', 'expected' => TRUE); + $test_cases[3] = array('type' => 'node', 'bundle' => 'invalid-bundle', 'expected' => FALSE); + $test_cases[4] = array('type' => 'user', 'expected' => TRUE); + $test_cases[5] = array('type' => 'invalid-entity', 'expected' => FALSE); + foreach ($test_cases as $test_case) { + $test_case += array('bundle' => NULL); + $this->assertMetatagEntitySupportsMetatags($test_case['type'], $test_case['bundle'], $test_case['expected']); + } + + variable_set('metatag_test_entity_info_disable', TRUE); + drupal_static_reset('metatag_entity_supports_metatags'); + entity_info_cache_clear(); + + $test_cases[2]['expected'] = FALSE; + $test_cases[4]['expected'] = FALSE; + foreach ($test_cases as $test_case) { + $test_case += array('bundle' => NULL); + $this->assertMetatagEntitySupportsMetatags($test_case['type'], $test_case['bundle'], $test_case['expected']); + } + } + + function assertMetatagEntitySupportsMetatags($type, $bundle, $expected) { + return $this->assertEqual( + metatag_entity_supports_metatags($type, $bundle), + $expected, + t("metatag_entity_supports_metatags(:type, :bundle) was :expected", array( + ':type' => var_export($type, TRUE), + ':bundle' => var_export($bundle, TRUE), + ':expected' => var_export($expected, TRUE), + )) + ); + } +} diff --git a/sites/all/modules/metatag/metatag.theme.inc b/sites/all/modules/metatag/metatag.theme.inc new file mode 100644 index 0000000000000000000000000000000000000000..20f4fa2faae47658b7b3bb37c21bf45ebeb9a771 --- /dev/null +++ b/sites/all/modules/metatag/metatag.theme.inc @@ -0,0 +1,58 @@ +<?php + +/** + * @file + * Theme callbacks for the metatag module. + */ + +/** + * Theme callback for a normal meta tag. + * + * The format is: + * <meta name="[name]" content="[value]" /> + */ +function theme_metatag($variables) { + $element = &$variables['element']; + element_set_attributes($element, array('name', '#value' => 'content')); + unset($element['#value']); + return theme('html_tag', $variables); +} + +/** + * Theme callback for a normal meta tag. + * + * The format is: + * <meta http-equiv="[name]" content="[value]" /> + */ +function theme_metatag_http_equiv($variables) { + $element = &$variables['element']; + element_set_attributes($element, array('#name' => 'http-equiv', '#value' => 'content')); + unset($element['#value']); + return theme('html_tag', $variables); +} + +/** + * Theme callback for a rel link tag. + * + * The format is: + * <link rel="[name]" href="[value]" /> + */ +function theme_metatag_link_rel($variables) { + $element = &$variables['element']; + element_set_attributes($element, array('#name' => 'rel', '#value' => 'href')); + unset($element['#value']); + return theme('html_tag', $variables); +} + +/** + * Theme callback for a rev link tag. + * + * The format is: + * <link rev="[name]" href="[value]" /> + */ +function theme_metatag_link_rev($variables) { + $element = &$variables['element']; + element_set_attributes($element, array('#name' => 'rev', '#value' => 'href')); + unset($element['#value']); + return theme('html_tag', $variables); +} diff --git a/sites/all/modules/metatag/metatag.vertical-tabs.js b/sites/all/modules/metatag/metatag.vertical-tabs.js new file mode 100644 index 0000000000000000000000000000000000000000..b207b2cfe04f1b29e21c34251216a524b33c8c70 --- /dev/null +++ b/sites/all/modules/metatag/metatag.vertical-tabs.js @@ -0,0 +1,47 @@ + +(function ($) { + +Drupal.behaviors.metatagFieldsetSummaries = { + attach: function (context) { + $('fieldset.metatags-form', context).drupalSetSummary(function (context) { + var vals = []; + $("input[type='text'], select, textarea", context).each(function() { + var default_name = $(this).attr('name').replace(/\[value\]/, '[default]'); + var default_value = $("input[type='hidden'][name='" + default_name + "']", context); + if (default_value.length && default_value.val() == $(this).val()) { + // Meta tag has a default value and form value matches default value. + return true; + } + else if (!default_value.length && !$(this).val().length) { + // Meta tag has no default value and form value is empty. + return true; + } + var label = $("label[for='" + $(this).attr('id') + "']").text(); + vals.push(Drupal.t('@label: @value', { + '@label': $.trim(label), + '@value': Drupal.truncate($(this).val(), 25) || Drupal.t('None') + })); + }); + if (vals.length === 0) { + return Drupal.t('Using defaults'); + } + else { + return vals.join('<br />'); + } + }); + } +}; + +/** + * Encode special characters in a plain-text string for display as HTML. + */ +Drupal.truncate = function (str, limit) { + if (str.length > limit) { + return str.substr(0, limit) + '...'; + } + else { + return str; + } +}; + +})(jQuery); diff --git a/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.info b/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.info new file mode 100644 index 0000000000000000000000000000000000000000..32df12e2ad61a7a9cc3bfdcc5ac15eb3d96e264f --- /dev/null +++ b/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.info @@ -0,0 +1,12 @@ +name = Open Graph meta tags +description = Provides support for open graph meta tags. +package = Meta tags +core = 7.x +dependencies[] = metatag + +; Information added by drupal.org packaging script on 2012-07-13 +version = "7.x-1.0-alpha6+1-dev" +core = "7.x" +project = "metatag" +datestamp = "1342182783" + diff --git a/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.metatag.inc b/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.metatag.inc new file mode 100644 index 0000000000000000000000000000000000000000..a6d9dc7b0454cff7bb6b611bd8b7d5fcfaaa7870 --- /dev/null +++ b/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.metatag.inc @@ -0,0 +1,192 @@ +<?php + +/** + * @file + * Metatag integration for the metatag_opengraph module. + */ + +/** + * Implements hook_metatag_config_default_alter(). + */ +function metatag_opengraph_metatag_config_default_alter(array &$configs) { + foreach ($configs as &$config) { + switch ($config->instance) { + case 'global': + $config->config += array( + 'og:type' => array('value' => 'article'), + 'og:title' => array('value' => '[current-page:title]'), + 'og:site_name' => array('value' => '[site:name]'), + 'og:url' => array('value' => '[current-page:url]'), + ); + break; + case 'global:frontpage': + $config->config += array( + 'og:type' => array('value' => 'website'), + 'og:title' => array('value' => '[site:name]'), + 'og:url' => array('value' => '[site:url]'), + ); + break; + case 'node': + $config->config += array( + 'og:title' => array('value' => '[node:title]'), + 'og:description' => array('value' => '[node:summary]'), + ); + break; + case 'taxonomy_term': + $config->config += array( + 'og:title' => array('value' => '[term:name]'), + 'og:description' => array('value' => '[term:description]'), + ); + break; + case 'user': + $config->config += array( + 'og:type' => array('value' => 'profile'), + 'og:title' => array('value' => '[user:name]'), + ); + if (variable_get('user_pictures')) { + $config->config += array( + 'og:image' => array('value' => '[user:picture:url]'), + ); + } + + break; + } + } +} + +/** + * Implements hook_metatag_info(). + */ +function metatag_opengraph_metatag_info() { + $info['groups']['open-graph'] = array( + 'label' => t('Open Graph'), + ); + + $info['tags']['og:title'] = array( + 'label' => t('Open Graph title'), + 'description' => t('The title of your object as it should appear within the graph, e.g., <em>The Rock</em>.'), + 'class' => 'DrupalTextMetaTag', + 'group' => 'open-graph', + 'element' => array( + '#theme' => 'metatag_opengraph', + ), + ); + $info['tags']['og:type'] = array( + 'label' => t('Open Graph type'), + 'description' => t('The type of your object, e.g., <em>movie</em>.'), + 'class' => 'DrupalTextMetaTag', + 'group' => 'open-graph', + 'form' => array( + '#type' => 'select', + '#options' => _metatag_opengraph_type_options(), + '#empty_option' => t('- None -'), + ), + 'element' => array( + '#theme' => 'metatag_opengraph', + ), + ); + //if (module_exists('select_or_other')) { + // $info['tags']['og:type']['form']['#type'] = 'select_or_other'; + //} + $info['tags']['og:image'] = array( + 'label' => t('Open Graph image'), + 'description' => t('An image URL which should represent your object within the graph. The image must be at least 50px by 50px and have a maximum aspect ratio of 3:1. We support PNG, JPEG and GIF formats.'), + 'class' => 'DrupalTextMetaTag', + 'group' => 'open-graph', + 'element' => array( + '#theme' => 'metatag_opengraph', + ), + ); + $info['tags']['og:url'] = array( + 'label' => t('Open Graph URL'), + 'description' => t('The canonical URL of your object that will be used as its permanent ID in the graph, e.g., <em>http://www.imdb.com/title/tt0117500/</em>.'), + 'class' => 'DrupalTextMetaTag', + 'group' => 'open-graph', + 'element' => array( + '#theme' => 'metatag_opengraph', + ), + ); + $info['tags']['og:site_name'] = array( + 'label' => t('Open Graph site name'), + 'description' => t('A human-readable name for your site, e.g., <em>IMDb</em>.'), + 'class' => 'DrupalTextMetaTag', + 'group' => 'open-graph', + 'context' => array('global'), + 'element' => array( + '#theme' => 'metatag_opengraph', + ), + ); + $info['tags']['og:description'] = array( + 'label' => t('Open Graph description'), + 'description' => t('A one to two sentence description of your page.'), + 'group' => 'open-graph', + 'class' => 'DrupalTextMetaTag', + 'element' => array( + '#theme' => 'metatag_opengraph', + ), + ); + + return $info; +} + +function _metatag_opengraph_type_options() { + $options = array( + t('Activities') => array( + 'activity' => t('Activity'), + 'sport' => t('Sport'), + ), + t('Businesses') => array( + 'bar' => t('Bar'), + 'company' => t('Company'), + 'cafe' => t('Cafe'), + 'hotel' => t('Hotel'), + 'restaurant' => t('Restaurant'), + ), + t('Groups') => array( + 'cause' => t('Cause'), + 'sports_league' => t('Sports league'), + 'sports_team' => t('Sports team'), + ), + t('Organizations') => array( + 'band' => t('Band'), + 'government' => t('Government'), + 'non_profit' => t('Non-profit'), + 'school' => t('School'), + 'university' => t('University'), + ), + t('People') => array( + 'actor' => t('Actor'), + 'athlete' => t('Athlete'), + 'author' => t('Author'), + 'director' => t('Director'), + 'musician' => t('Musician'), + 'politician' => t('Politician'), + 'profile' => t('Profile'), + 'public_figure' => t('Public figure'), + ), + t('Places') => array( + 'city' => t('City'), + 'country' => t('Country'), + 'landmark' => t('Landmark'), + 'state_province' => t('State or province'), + ), + t('Products and Entertainment') => array( + 'album' => t('Album'), + 'book' => t('Book'), + 'drink' => t('Drink'), + 'food' => t('Food'), + 'game' => t('Game'), + 'movie' => t('Movie'), + 'product' => t('Product'), + 'song' => t('Song'), + 'tv_show' => t('TV show'), + ), + t('Websites') => array( + 'blog' => t('Blog'), + 'website' => t('Website'), + 'article' => t('Article'), + ), + ); + + return $options; +} diff --git a/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.module b/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.module new file mode 100644 index 0000000000000000000000000000000000000000..d94e7d4551efc875270699c4c0483d5eeb5ced01 --- /dev/null +++ b/sites/all/modules/metatag/metatag_opengraph/metatag_opengraph.module @@ -0,0 +1,77 @@ +<?php + +/** + * Implements hook_preprocess_html(). + */ +function metatag_opengraph_preprocess_html(&$variables) { + // The RDF module adds the Open Graph namespace itself. + // @see rdf_rdf_namespaces() + if (!module_exists('rdf')) { + $variables['rdf_namespaces'] .= "\n xmlns:og=\"http://ogp.me/ns#\""; + } +} + +/** + * Implements hook_ctools_plugin_api(). + */ +function metatag_opengraph_ctools_plugin_api($owner, $api) { + if ($owner == 'metatag' && $api == 'metatag') { + return array('version' => 1); + } +} + +/** + * Implements hook_theme(). + */ +function metatag_opengraph_theme() { + $info['metatag_opengraph'] = array( + 'render element' => 'element', + ); + + return $info; +} + +/** + * Theme callback for an OpenGraph meta tag. + */ +function theme_metatag_opengraph($variables) { + $element = &$variables['element']; + element_set_attributes($element, array('#name' => 'property', '#value' => 'content')); + unset($element['#value']); + return theme('html_tag', $variables); +} + +/* +og:title = [node:title] / [user:name] +og:type = article / profile +og:image = ? / [user:picture:url] +og:url = [node:url] / [user:url] +og:description +og:site_name = [site:name] + +og:latitude +og:longitude +og:street-address +og:locality +og:region +og:postal-code +og:country-name + +og:email +og:phone_number +og:fax_number + +og:video +og:video:height +og:video:width +og:video:type + +og:audio +og:audio:title +og:audio:artist +og:audio:album +og:audio:type + +og:upc +og:isbn +*/ diff --git a/sites/all/modules/metatag/metatag_ui/metatag_ui.info b/sites/all/modules/metatag/metatag_ui/metatag_ui.info new file mode 100644 index 0000000000000000000000000000000000000000..801f2c87e7b8b1485f64b21bd7ac899d4328d863 --- /dev/null +++ b/sites/all/modules/metatag/metatag_ui/metatag_ui.info @@ -0,0 +1,14 @@ +name = Meta tag UI +description = User interface for the Meta tag API. +package = Meta tags +core = 7.x +dependencies[] = metatag +dependencies[] = ctools +hidden = TRUE + +; Information added by drupal.org packaging script on 2012-07-13 +version = "7.x-1.0-alpha6+1-dev" +core = "7.x" +project = "metatag" +datestamp = "1342182783" + diff --git a/sites/all/modules/metatag/tests/metatag_test.info b/sites/all/modules/metatag/tests/metatag_test.info new file mode 100644 index 0000000000000000000000000000000000000000..451067fbaa435575422598278653467a376c0c06 --- /dev/null +++ b/sites/all/modules/metatag/tests/metatag_test.info @@ -0,0 +1,12 @@ +name = Meta Tag Test +description = Testing module for metatag.module +core = 7.x +dependencies[] = metatag +hidden = TRUE + +; Information added by drupal.org packaging script on 2012-07-13 +version = "7.x-1.0-alpha6+1-dev" +core = "7.x" +project = "metatag" +datestamp = "1342182783" + diff --git a/sites/all/modules/metatag/tests/metatag_test.metatag.inc b/sites/all/modules/metatag/tests/metatag_test.metatag.inc new file mode 100644 index 0000000000000000000000000000000000000000..bed4abc69c946c2f5afa68dd075e0f10dd02e481 --- /dev/null +++ b/sites/all/modules/metatag/tests/metatag_test.metatag.inc @@ -0,0 +1,53 @@ +<?php + +/** + * Implements hook_metatag_config_default(). + */ +function metatag_test_metatag_config_default() { + $configs = array(); + + $config = new stdClass(); + $config->instance = 'test'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'description' => array('value' => 'Test description'), + ); + $configs[$config->instance] = $config; + + $config = new stdClass(); + $config->instance = 'test:foo'; + $config->api_version = 1; + $config->disabled = FALSE; + $config->config = array( + 'description' => array('value' => 'Test foo description'), + 'title' => array('value' => 'Test title'), + 'test:foo' => array('value' => 'foobar'), + ); + $configs[$config->instance] = $config; + + return $configs; +} + +/** + * Implements hook_metatag_config_default_alter(). + */ +function metatag_test_metatag_config_default_alter(array &$configs) { + if (isset($configs['test:foo'])) { + $configs['test:foo']->config['title']['value'] = 'Test altered title'; + } +} + +/** + * Implements hook_metatag_info(). + */ +function metatag_test_metatag_info() { + $info['test:foo'] = array( + 'label' => t('Foo meta tag'), + 'description' => t('Testing metatag.'), + 'class' => 'DrupalTextMetaTag', + 'group' => t('Testing'), + ); + + return $info; +} diff --git a/sites/all/modules/metatag/tests/metatag_test.module b/sites/all/modules/metatag/tests/metatag_test.module new file mode 100644 index 0000000000000000000000000000000000000000..aefb329f1c5682fcd537795bde0cbbaab7768fe1 --- /dev/null +++ b/sites/all/modules/metatag/tests/metatag_test.module @@ -0,0 +1,20 @@ +<?php + +/** + * Implements hook_ctools_plugin_api(). + */ +function metatag_test_ctools_plugin_api($owner, $api) { + if ($owner == 'metatag' && $api == 'metatag') { + return array('version' => 1); + } +} + +/** + * Implements hook_entity_info_alter(). + */ +function metatag_test_entity_info_alter(&$info) { + if (variable_get('metatag_test_entity_info_disable')) { + $info['node']['bundles']['page']['metatags'] = FALSE; + $info['user']['metatags'] = FALSE; + } +} diff --git a/sites/all/modules/unl/unl.module b/sites/all/modules/unl/unl.module index 6205c64075a30dbfca1ff58e1e844b0af1ca3837..c6dbc5775f0f0021260b7cc3df02ee4a95a1b95d 100644 --- a/sites/all/modules/unl/unl.module +++ b/sites/all/modules/unl/unl.module @@ -152,8 +152,8 @@ function unl_page_build(&$page) { function unl_field_attach_view_alter(&$output, $context) { // Replace the field named field_hrorgunit containing an org unit number with that unit's listing from the UNL directory foreach (element_children($output) as $field_name) { - $element = &$output[$field_name]; - switch ($element['#field_name']) { + $element = isset($output[$field_name]['#field_name']) ? $output[$field_name]['#field_name'] : ''; + switch ($element) { case 'field_hrorgunit': $result = file_get_contents('http://directory.unl.edu/departments/?view=deptlistings&org_unit='.$element['#items'][0]['value'].'&format=partial'); if (!empty($result) && $result != '<div id="all_employees"></div>') { @@ -1537,22 +1537,22 @@ function unl_filter_info() /** * Implementation of hook_filter_FILTER_process pseudo-hook - * - * Replace any instances of [[node:X]] in the $text with the content of node X's body. + * + * Replace any instances of [[node:X]] in the $text with the content of node X's body. */ function unl_filter_embed_process($text, $filter, $format, $langcode, $cache, $cache_id) { static $processed_hashes = array(); - + $text_hash = hash('sha256', $text); if (in_array($text_hash, array_keys($processed_hashes))) { // Possible recursion detected, return the cache result. return $processed_hashes[$text_hash]; } - + // In case of recursion, set the cached result to this until we have the real result. $processed_hashes[$text_hash] = 'Error: Cannot embed a node in itself..'; - + $matches = NULL; preg_match_all('/\[\[node:([0-9]+)\]\]/', $text, $matches); $node_ids = $matches[1]; @@ -1561,8 +1561,8 @@ function unl_filter_embed_process($text, $filter, $format, $langcode, $cache, $c foreach ($node_ids as $node_id) { $content = node_view($nodes[$node_id]); $replace_array["[[node:$node_id]]"] = PHP_EOL . "<!-- Node $node_id start -->" . PHP_EOL - . render($content['body']) - . PHP_EOL . "<!-- Node $node_id end -->" . PHP_EOL; + . render($content['body']) + . PHP_EOL . "<!-- Node $node_id end -->" . PHP_EOL; } $text = strtr($text, $replace_array); // Set the cached result to the real result. @@ -1572,20 +1572,20 @@ function unl_filter_embed_process($text, $filter, $format, $langcode, $cache, $c /** * Implementation of hook_filter_FILTER_process pseudo-hook - * - * Replace any instances of <!--#include virtual="url"--> with the content + * + * Replace any instances of <!--#include virtual="url"--> with the content * found at that URL. If the url is in the unl.edu domain, format=partial * will be added to the query string. */ function unl_filter_ssi_process($text, $filter, $format, $langcode, $cache, $cache_id) { $matches = NULL; preg_match_all('/<!-- *#include +virtual=((".*")|(\'.*\')) *-->/', $text, $matches); - + $replacements = array(); - + foreach ($matches[1] as $match_index => $match) { $full_match = $matches[0][$match_index]; - + // Break down the URL target then rebuild it as absolute. $url = substr($match, 1, -1); $parts = parse_url($url); @@ -1606,8 +1606,8 @@ function unl_filter_ssi_process($text, $filter, $format, $langcode, $cache, $cac $parts['path'] = '/'; } $url = $parts['scheme'] . '://' . $parts['host'] . $parts['path']; - - + + // If this is a request to another UNL site, add format=partial to the query. if (substr($parts['host'], -7) == 'unl.edu') { if (isset($parts['query']) && $parts['query']) { @@ -1617,7 +1617,7 @@ function unl_filter_ssi_process($text, $filter, $format, $langcode, $cache, $cac } $parts['query'] .= 'format=partial'; } - + // Finish rebuilding the URL. if (isset($parts['query'])) { $url .= '?' . $parts['query']; @@ -1625,18 +1625,18 @@ function unl_filter_ssi_process($text, $filter, $format, $langcode, $cache, $cac if (isset($parts['fragment'])) { $url .= '#' . $parts['fragment']; } - + $content = file_get_contents($url); $replacements[$full_match] = PHP_EOL . '<!-- Begin content from ' . $url . ' -->' . PHP_EOL . $content . PHP_EOL . '<!-- End content from ' . $url . ' -->' . PHP_EOL; } - + foreach ($replacements as $from => $to) { $text = str_replace($from, $to, $text); } - + return $text; } diff --git a/sites/all/themes/unl_wdn/template.php b/sites/all/themes/unl_wdn/template.php index 1095a8b6b7b9a89504d4a85e3331c1f9717f899e..2f87069c8dde7e03ff30c5c5cfda227bcff5f17f 100644 --- a/sites/all/themes/unl_wdn/template.php +++ b/sites/all/themes/unl_wdn/template.php @@ -68,14 +68,16 @@ function unl_wdn_preprocess_html(&$vars, $hook) { } } - // Set the <title> tag to UNL format: Page Title | Site Name | University of Nebraska–Lincoln - if ($vars['is_front']) { - unset($vars['head_title_array']['title']); - } - if (variable_get('site_name') != 'University of Nebraska–Lincoln') { - $vars['head_title_array'] = array_merge($vars['head_title_array'], array('UNL' => 'University of Nebraska–Lincoln')); + if (!module_exists('metatag')) { + // Set the <title> tag to UNL format: Page Title | Site Name | University of Nebraska–Lincoln + if ($vars['is_front']) { + unset($vars['head_title_array']['title']); + } + if (variable_get('site_name') != 'University of Nebraska–Lincoln') { + $vars['head_title_array'] = array_merge($vars['head_title_array'], array('UNL' => 'University of Nebraska–Lincoln')); + } + $vars['head_title'] = implode(' | ', $vars['head_title_array']); } - $vars['head_title'] = implode(' | ', $vars['head_title_array']); } /**