<p>So the problem you're running into is all about context. Twig operates in the context of the http request for the parent page; so any headers you add via Twig will be added to the page http header, which is not what you want.</p>

<p>This could be done server-side, as the article you reference mentions. But it becomes a bit more involved when we're dealing with dynamic content, which presumably we are if a CMS is in the mix.</p>

<p>Because what you need is something that will intercept the http requests for documents you want to affect the header of, and then set it based on the dynamic page where it's coming from.</p>

<p>You could accomplish this via a plugin by writing a controller that sets the headers and then returns the actual file. Then in your Twig code, you'd link to the controller not the PDF file.</p>

<p>If you're using <a href="https://github.com/nystudio107/craft-seomatic" rel="nofollow noreferrer">SEOmatic</a> for Craft CMS 3, you can use the built in <a href="https://github.com/nystudio107/craft-seomatic#helper-functions-seomatichelper" rel="nofollow noreferrer">seomatic.helper.seoFileLink()</a> function to do all of this for you.</p>

CC BY-SA 3.0
2018-03-21T17:49:00.950Z
Thanks a lot for the reply, Andrew! I think you're right - the solution would need to be some sort of plugin, Craft 3 Yii module (I read your guide on this - super helpful, thank you!), or potentially with .htaccess using some combination of HTTP_HOST or Request_URI to dynamically set the canonical URL. 

Also, super cool feature for SEOmatic! That could make life a lot easier rather than having to build a plugin / module just for this purpose.

I'll think about the best way to implement this based on your suggestions / different options.

Really appreciate your help!
dpayne
CC BY-SA 3.0
2018-03-22T00:02:23.330Z
Hey @andrew.welch, I've been messing around the with seoFileLink() function in SEOmatic and ran into a few issues with my use case. 1. The function causes the Google PDF preview to show a "no preview available" message, rather the PDF contents as it did before. Embedding via <embed> no longer shows the PDF either. 2. Clicking on links to the PDF that go through the function seem to always force a download, regardless of how I set INLINE (could be user error). Not sure if / when those are fixable but SEOmatic seems to be the best solution to solving this problem if those things can work.
dpayne
CC BY-SA 3.0
2018-03-22T03:14:03.717Z
Do me a favor and file an issue with the code you're using, so I can test it? https://github.com/nystudio107/craft-seomatic/issues
andrew.welch
CC BY-SA 3.0
2018-03-22T14:31:46.280Z
So I completely refactored how the `seoFileLink()` function works in SEOmatic `3.0.0-beta.13` -- give it a whirl? https://github.com/nystudio107/craft-seomatic/releases/tag/3.0.0-beta.13
andrew.welch
CC BY-SA 3.0
2018-03-22T18:47:44.337Z
Holy cow - looks like it works! It added the header link to the PDF and no longer forces a download from a link click. I'm going to experiment with the plugin some more but you may have gotten yourself a new customer :). Thanks so much!
dpayne
CC BY-SA 3.0
2018-03-22T19:01:23.033Z
Great, glad to hear it's working for you now.
andrew.welch
CC BY-SA 3.0
2018-03-21T15:00:16.667Z
2018-03-21T18:38:48.237Z
2018-03-21T18:38:48.237Z
andrew.welch
<p>I'm working on project where I would like to directly embed PDFs onto web pages. We'll be using Google's PDF viewer as the embed tool and implementing via a macro.</p>

<p>Here is the macro as it stands now: </p>

<pre><code>{% macro pdfEmbed(pdfLink, width="580", height="480") %}

    &lt;iframe src="https://drive.google.com/viewerng/viewer?embedded=true&amp;url={{ pdfLink }}" width="{{width}}px" height="{{height}}px"&gt;&lt;/iframe&gt;

{% endmacro %}
</code></pre>

<p>For SEO purposes, I'd like to set a rel="canonical" on the PDF to point to the entry on which the PDF is embedded so Google knows to index the parent page and not the PDF. From what I've read, the general best practice for how to do this with embedded PDFs is via HTTP headers. See here for more detail: <a href="https://moz.com/blog/how-to-advanced-relcanonical-http-headers" rel="nofollow noreferrer">https://moz.com/blog/how-to-advanced-relcanonical-http-headers</a></p>

<p>I'm struggling with how to implement it in practice. I think the best method would be to use <code>{% header %}</code> tag within the macro but I'm not sure if there's a way to target that at just PDF files? If that doesn't work, .htaccess could be an option but then I lose the ability to dynamically set the canonical on the PDF based on the URL of the entry that houses the PDF.</p>

<p>What is the best way to do this in Craft? I’m running a Craft 3 site FYI. </p>

<p>Thanks!</p>

<entry><macro><seo><pdf>
How Do I Add a rel="canonical" HTTP Header to Embedded PDF Files?
# How Do I Add a rel="canonical" HTTP Header to Embedded PDF Files?

(Asked by: username_0 on 2018-03-20)

I'm working on project where I would like to directly embed PDFs onto web pages. We'll be using Google's PDF viewer as the embed tool and implementing via a macro.
Here is the macro as it stands now: 
{% macro pdfEmbed(pdfLink, width="580", height="480") %}

    

{% endmacro %}

For SEO purposes, I'd like to set a rel="canonical" on the PDF to point to the entry on which the PDF is embedded so Google knows to index the parent page and not the PDF. From what I've read, the general best practice for how to do this with embedded PDFs is via HTTP headers. See here for more detail: https://moz.com/blog/how-to-advanced-relcanonical-http-headers
I'm struggling with how to implement it in practice. I think the best method would be to use {% header %} tag within the macro but I'm not sure if there's a way to target that at just PDF files? If that doesn't work, .htaccess could be an option but then I lose the ability to dynamically set the canonical on the PDF based on the URL of the entry that houses the PDF.
What is the best way to do this in Craft? I’m running a Craft 3 site FYI. 
Thanks!

**Tags:** entry, macro, seo, pdf

---

## 1 answers

### Answer by username_1 on 2018-03-21. Score: 2 | Accepted answer

So the problem you're running into is all about context. Twig operates in the context of the http request for the parent page; so any headers you add via Twig will be added to the page http header, which is not what you want.

This could be done server-side, as the article you reference mentions. But it becomes a bit more involved when we're dealing with dynamic content, which presumably we are if a CMS is in the mix.

Because what you need is something that will intercept the http requests for documents you want to affect the header of, and then set it based on the dynamic page where it's coming from.

You could accomplish this via a plugin by writing a controller that sets the headers and then returns the actual file. Then in your Twig code, you'd link to the controller not the PDF file.

If you're using [SEOmatic](https://github.com/nystudio107/craft-seomatic) for Craft CMS 3, you can use the built in [seomatic.helper.seoFileLink()](https://github.com/nystudio107/craft-seomatic#helper-functions-seomatichelper) function to do all of this for you.

> **Comments:**
> **username_0**: Thanks a lot for the reply, Andrew! I think you're right - the solution would need to be some sort of plugin, Craft 3 Yii module (I read your guide on this - super helpful, thank you!), or potentially with .htaccess using some combination of HTTP_HOST or Request_URI to dynamically set the canonical URL.   Also, super cool feature for SEOmatic! That could make life a lot easier rather than having to build a plugin / module just for this purpose.  I'll think about the best way to implement this based on your suggestions / different options.  Really appreciate your help!  
> **username_0**: Hey @andrew.welch, I've been messing around the with seoFileLink() function in SEOmatic and ran into a few issues with my use case. 1. The function causes the Google PDF preview to show a "no preview available" message, rather the PDF contents as it did before. Embedding via <embed> no longer shows the PDF either. 2. Clicking on links to the PDF that go through the function seem to always force a download, regardless of how I set INLINE (could be user error). Not sure if / when those are fixable but SEOmatic seems to be the best solution to solving this problem if those things can work.  
> **username_1**: Do me a favor and file an issue with the code you're using, so I can test it? https://github.com/nystudio107/craft-seomatic/issues  
> **username_1**: So I completely refactored how the `seoFileLink()` function works in SEOmatic `3.0.0-beta.13` -- give it a whirl? https://github.com/nystudio107/craft-seomatic/releases/tag/3.0.0-beta.13  
> **username_0**: Holy cow - looks like it works! It added the header link to the PDF and no longer forces a download from a link click. I'm going to experiment with the plugin some more but you may have gotten yourself a new customer :). Thanks so much!  
> **username_1**: Great, glad to hear it's working for you now.  

---

